From e39f2b025da65ebe13b2e9e4ed5cc07f47243700 Mon Sep 17 00:00:00 2001 From: Simon Szustkowski Date: Wed, 3 Sep 2014 10:49:59 +0200 Subject: [PATCH] Fetched missing gems --- .gems/cache/addressable-2.3.6.gem | Bin 0 -> 98304 bytes .gems/cache/buftok-0.2.0.gem | Bin 0 -> 8192 bytes .gems/cache/equalizer-0.0.9.gem | Bin 0 -> 12288 bytes .gems/cache/faraday-0.9.0.gem | Bin 0 -> 57344 bytes .gems/cache/http-0.6.2.gem | Bin 0 -> 66560 bytes .gems/cache/http_parser.rb-0.6.0.gem | Bin 0 -> 177664 bytes .gems/cache/memoizable-0.4.2.gem | Bin 0 -> 13312 bytes .gems/cache/multipart-post-2.0.0.gem | Bin 0 -> 11264 bytes .gems/cache/naught-1.0.0.gem | Bin 0 -> 18432 bytes .gems/cache/simple_oauth-0.2.0.gem | Bin 0 -> 11776 bytes .gems/cache/thread_safe-0.3.4.gem | Bin 0 -> 117760 bytes .../cdesc-PunycodeBadInput.ri | Bin 0 -> 502 bytes .../cdesc-PunycodeBigOutput.ri | Bin 0 -> 526 bytes .../cdesc-PunycodeOverflow.ri | Bin 0 -> 523 bytes .../ri/Addressable/IDNA/cdesc-IDNA.ri | Bin 0 -> 5274 bytes .../IDNA/lookup_unicode_combining_class-c.ri | Bin 0 -> 309 bytes .../IDNA/lookup_unicode_compatibility-c.ri | Bin 0 -> 305 bytes .../IDNA/lookup_unicode_composition-c.ri | Bin 0 -> 300 bytes .../IDNA/lookup_unicode_lowercase-c.ri | Bin 0 -> 297 bytes .../ri/Addressable/IDNA/punycode_adapt-c.ri | Bin 0 -> 355 bytes .../Addressable/IDNA/punycode_basic%3f-c.ri | Bin 0 -> 279 bytes .../ri/Addressable/IDNA/punycode_decode-c.ri | Bin 0 -> 277 bytes .../IDNA/punycode_decode_digit-c.ri | Bin 0 -> 510 bytes .../IDNA/punycode_delimiter%3f-c.ri | Bin 0 -> 287 bytes .../ri/Addressable/IDNA/punycode_encode-c.ri | Bin 0 -> 277 bytes .../IDNA/punycode_encode_digit-c.ri | Bin 0 -> 283 bytes .../ri/Addressable/IDNA/to_ascii-c.ri | Bin 0 -> 262 bytes .../ri/Addressable/IDNA/to_unicode-c.ri | Bin 0 -> 266 bytes .../ri/Addressable/IDNA/unicode_compose-c.ri | Bin 0 -> 278 bytes .../IDNA/unicode_compose_pair-c.ri | Bin 0 -> 294 bytes .../Addressable/IDNA/unicode_decompose-c.ri | Bin 0 -> 282 bytes .../IDNA/unicode_decompose_hangul-c.ri | Bin 0 -> 297 bytes .../ri/Addressable/IDNA/unicode_downcase-c.ri | Bin 0 -> 546 bytes .../IDNA/unicode_normalize_kc-c.ri | Bin 0 -> 286 bytes .../IDNA/unicode_sort_canonical-c.ri | Bin 0 -> 292 bytes .../ri/Addressable/Template/%3d%3d-i.ri | Bin 0 -> 845 bytes .../cdesc-InvalidTemplateOperatorError.ri | Bin 0 -> 575 bytes .../cdesc-InvalidTemplateValueError.ri | Bin 0 -> 557 bytes .../Template/MatchData/%5b%5d-i.ri | Bin 0 -> 1117 bytes .../Template/MatchData/captures-i.ri | Bin 0 -> 272 bytes .../Template/MatchData/cdesc-MatchData.ri | Bin 0 -> 923 bytes .../Template/MatchData/inspect-i.ri | Bin 0 -> 477 bytes .../Addressable/Template/MatchData/keys-i.ri | Bin 0 -> 264 bytes .../Template/MatchData/mapping-i.ri | 5 + .../Addressable/Template/MatchData/names-i.ri | Bin 0 -> 266 bytes .../Addressable/Template/MatchData/new-c.ri | Bin 0 -> 582 bytes .../Template/MatchData/post_match-i.ri | Bin 0 -> 276 bytes .../Template/MatchData/pre_match-i.ri | Bin 0 -> 475 bytes .../Template/MatchData/string-i.ri | Bin 0 -> 268 bytes .../Template/MatchData/template-i.ri | 2 + .../Addressable/Template/MatchData/to_a-i.ri | Bin 0 -> 447 bytes .../Addressable/Template/MatchData/to_s-i.ri | Bin 0 -> 421 bytes .../Addressable/Template/MatchData/uri-i.ri | 2 + .../Template/MatchData/values-i.ri | Bin 0 -> 583 bytes .../Template/MatchData/values_at-i.ri | Bin 0 -> 671 bytes .../Template/MatchData/variables-i.ri | Bin 0 -> 617 bytes .../cdesc-TemplateOperatorAbortedError.ri | Bin 0 -> 575 bytes .../ri/Addressable/Template/cdesc-Template.ri | Bin 0 -> 1734 bytes .../ri/Addressable/Template/eql%3f-i.ri | Bin 0 -> 415 bytes .../ri/Addressable/Template/expand-i.ri | Bin 0 -> 2609 bytes .../ri/Addressable/Template/extract-i.ri | Bin 0 -> 2644 bytes .../ri/Addressable/Template/inspect-i.ri | Bin 0 -> 477 bytes .../ri/Addressable/Template/join_values-i.ri | Bin 0 -> 817 bytes .../ri/Addressable/Template/keys-i.ri | Bin 0 -> 252 bytes .../ri/Addressable/Template/match-i.ri | Bin 0 -> 2813 bytes .../ri/Addressable/Template/new-c.ri | Bin 0 -> 521 bytes .../Addressable/Template/normalize_keys-i.ri | Bin 0 -> 548 bytes .../Addressable/Template/normalize_value-i.ri | Bin 0 -> 641 bytes .../Template/ordered_variable_defaults-i.ri | Bin 0 -> 295 bytes .../Template/parse_template_pattern-i.ri | Bin 0 -> 712 bytes .../Addressable/Template/partial_expand-i.ri | Bin 0 -> 2139 bytes .../ri/Addressable/Template/pattern-i.ri | 2 + .../Template/transform_capture-i.ri | Bin 0 -> 1648 bytes .../Template/transform_partial_capture-i.ri | Bin 0 -> 1665 bytes .../Template/variable_defaults-i.ri | Bin 0 -> 553 bytes .../ri/Addressable/Template/variables-i.ri | Bin 0 -> 689 bytes .../ri/Addressable/URI/%2b-i.ri | Bin 0 -> 234 bytes .../ri/Addressable/URI/%3d%3d%3d-i.ri | Bin 0 -> 717 bytes .../ri/Addressable/URI/%3d%3d-i.ri | Bin 0 -> 656 bytes .../cdesc-CharacterClasses.ri | Bin 0 -> 1781 bytes .../InvalidURIError/cdesc-InvalidURIError.ri | Bin 0 -> 523 bytes .../ri/Addressable/URI/absolute%3f-i.ri | Bin 0 -> 517 bytes .../ri/Addressable/URI/authority%3d-i.ri | Bin 0 -> 451 bytes .../ri/Addressable/URI/authority-i.ri | Bin 0 -> 468 bytes .../ri/Addressable/URI/basename-i.ri | Bin 0 -> 418 bytes .../ri/Addressable/URI/cdesc-URI.ri | Bin 0 -> 3485 bytes .../ri/Addressable/URI/convert_path-c.ri | Bin 0 -> 1604 bytes .../ri/Addressable/URI/default_port-i.ri | Bin 0 -> 550 bytes .../ri/Addressable/URI/defer_validation-i.ri | Bin 0 -> 706 bytes .../ri/Addressable/URI/display_uri-i.ri | Bin 0 -> 651 bytes .../ri/Addressable/URI/dup-i.ri | Bin 0 -> 379 bytes .../ri/Addressable/URI/empty%3f-i.ri | Bin 0 -> 505 bytes .../ri/Addressable/URI/encode-c.ri | Bin 0 -> 964 bytes .../ri/Addressable/URI/encode_component-c.ri | Bin 0 -> 2237 bytes .../ri/Addressable/URI/eql%3f-i.ri | Bin 0 -> 669 bytes .../ri/Addressable/URI/escape-c.ri | Bin 0 -> 265 bytes .../ri/Addressable/URI/extname-i.ri | Bin 0 -> 460 bytes .../ri/Addressable/URI/form_encode-c.ri | Bin 0 -> 813 bytes .../ri/Addressable/URI/form_unencode-c.ri | Bin 0 -> 746 bytes .../ri/Addressable/URI/fragment%3d-i.ri | Bin 0 -> 445 bytes .../ri/Addressable/URI/fragment-i.ri | Bin 0 -> 401 bytes .../ri/Addressable/URI/freeze-i.ri | Bin 0 -> 414 bytes .../ri/Addressable/URI/hash-i.ri | Bin 0 -> 428 bytes .../ri/Addressable/URI/heuristic_parse-c.ri | Bin 0 -> 989 bytes .../ri/Addressable/URI/host%3d-i.ri | Bin 0 -> 421 bytes .../ri/Addressable/URI/host-i.ri | Bin 0 -> 385 bytes .../ri/Addressable/URI/hostname%3d-i.ri | Bin 0 -> 564 bytes .../ri/Addressable/URI/hostname-i.ri | Bin 0 -> 524 bytes .../ri/Addressable/URI/inferred_port-i.ri | Bin 0 -> 555 bytes .../ri/Addressable/URI/inspect-i.ri | Bin 0 -> 460 bytes .../ri/Addressable/URI/ip_based%3f-i.ri | Bin 0 -> 561 bytes .../ri/Addressable/URI/ip_based_schemes-c.ri | Bin 0 -> 463 bytes .../ri/Addressable/URI/join%21-i.ri | Bin 0 -> 526 bytes .../ri/Addressable/URI/join-c.ri | Bin 0 -> 762 bytes .../ri/Addressable/URI/join-i.ri | Bin 0 -> 492 bytes .../ri/Addressable/URI/merge%21-i.ri | Bin 0 -> 537 bytes .../ri/Addressable/URI/merge-i.ri | Bin 0 -> 759 bytes .../ri/Addressable/URI/new-c.ri | Bin 0 -> 1313 bytes .../ri/Addressable/URI/normalize%21-i.ri | Bin 0 -> 464 bytes .../ri/Addressable/URI/normalize-i.ri | Bin 0 -> 740 bytes .../Addressable/URI/normalize_component-c.ri | Bin 0 -> 2534 bytes .../ri/Addressable/URI/normalize_path-c.ri | Bin 0 -> 478 bytes .../Addressable/URI/normalized_authority-i.ri | Bin 0 -> 451 bytes .../ri/Addressable/URI/normalized_encode-c.ri | Bin 0 -> 1044 bytes .../Addressable/URI/normalized_fragment-i.ri | Bin 0 -> 447 bytes .../ri/Addressable/URI/normalized_host-i.ri | Bin 0 -> 431 bytes .../Addressable/URI/normalized_password-i.ri | Bin 0 -> 447 bytes .../ri/Addressable/URI/normalized_path-i.ri | Bin 0 -> 431 bytes .../ri/Addressable/URI/normalized_port-i.ri | Bin 0 -> 432 bytes .../ri/Addressable/URI/normalized_query-i.ri | Bin 0 -> 441 bytes .../ri/Addressable/URI/normalized_scheme-i.ri | Bin 0 -> 439 bytes .../ri/Addressable/URI/normalized_site-i.ri | Bin 0 -> 737 bytes .../ri/Addressable/URI/normalized_user-i.ri | Bin 0 -> 431 bytes .../Addressable/URI/normalized_userinfo-i.ri | Bin 0 -> 447 bytes .../ri/Addressable/URI/omit%21-i.ri | Bin 0 -> 531 bytes .../ri/Addressable/URI/omit-i.ri | Bin 0 -> 789 bytes .../ri/Addressable/URI/origin-i.ri | Bin 0 -> 442 bytes .../ri/Addressable/URI/parse-c.ri | Bin 0 -> 643 bytes .../ri/Addressable/URI/password%3d-i.ri | Bin 0 -> 445 bytes .../ri/Addressable/URI/password-i.ri | Bin 0 -> 401 bytes .../ri/Addressable/URI/path%3d-i.ri | Bin 0 -> 421 bytes .../ri/Addressable/URI/path-i.ri | Bin 0 -> 385 bytes .../ri/Addressable/URI/port%3d-i.ri | Bin 0 -> 428 bytes .../ri/Addressable/URI/port-i.ri | Bin 0 -> 505 bytes .../ri/Addressable/URI/port_mapping-c.ri | Bin 0 -> 467 bytes .../ri/Addressable/URI/query%3d-i.ri | Bin 0 -> 427 bytes .../ri/Addressable/URI/query-i.ri | Bin 0 -> 389 bytes .../ri/Addressable/URI/query_values%3d-i.ri | Bin 0 -> 1050 bytes .../ri/Addressable/URI/query_values-i.ri | Bin 0 -> 996 bytes .../ri/Addressable/URI/relative%3f-i.ri | Bin 0 -> 517 bytes .../ri/Addressable/URI/replace_self-i.ri | Bin 0 -> 610 bytes .../ri/Addressable/URI/request_uri%3d-i.ri | Bin 0 -> 453 bytes .../ri/Addressable/URI/request_uri-i.ri | Bin 0 -> 474 bytes .../ri/Addressable/URI/route_from-i.ri | Bin 0 -> 779 bytes .../ri/Addressable/URI/route_to-i.ri | Bin 0 -> 775 bytes .../ri/Addressable/URI/scheme%3d-i.ri | Bin 0 -> 433 bytes .../ri/Addressable/URI/scheme-i.ri | Bin 0 -> 393 bytes .../ri/Addressable/URI/site%3d-i.ri | Bin 0 -> 413 bytes .../ri/Addressable/URI/site-i.ri | Bin 0 -> 693 bytes .../ri/Addressable/URI/split_path-i.ri | Bin 0 -> 577 bytes .../ri/Addressable/URI/to_hash-i.ri | Bin 0 -> 420 bytes .../ri/Addressable/URI/to_s-i.ri | Bin 0 -> 534 bytes .../ri/Addressable/URI/to_str-i.ri | Bin 0 -> 347 bytes .../ri/Addressable/URI/unencode-c.ri | Bin 0 -> 1518 bytes .../Addressable/URI/unencode_component-c.ri | Bin 0 -> 307 bytes .../ri/Addressable/URI/unescape-c.ri | Bin 0 -> 287 bytes .../Addressable/URI/unescape_component-c.ri | Bin 0 -> 307 bytes .../ri/Addressable/URI/user%3d-i.ri | Bin 0 -> 421 bytes .../ri/Addressable/URI/user-i.ri | Bin 0 -> 385 bytes .../ri/Addressable/URI/userinfo%3d-i.ri | Bin 0 -> 445 bytes .../ri/Addressable/URI/userinfo-i.ri | Bin 0 -> 451 bytes .../ri/Addressable/URI/validate-i.ri | Bin 0 -> 314 bytes .../ri/Addressable/VERSION/cdesc-VERSION.ri | Bin 0 -> 719 bytes .../ri/Addressable/cdesc-Addressable.ri | Bin 0 -> 644 bytes .gems/doc/addressable-2.3.6/ri/cache.ri | Bin 0 -> 4300 bytes .../addressable-2.3.6/ri/page-README_md.ri | Bin 0 -> 3157 bytes .../cdesc-BufferedTokenizer.ri | Bin 0 -> 852 bytes .../ri/BufferedTokenizer/extract-i.ri | Bin 0 -> 805 bytes .../ri/BufferedTokenizer/flush-i.ri | Bin 0 -> 407 bytes .../ri/BufferedTokenizer/new-c.ri | Bin 0 -> 838 bytes .gems/doc/buftok-0.2.0/ri/cache.ri | Bin 0 -> 371 bytes .../ri/Equalizer/Methods/%3d%3d-i.ri | Bin 0 -> 609 bytes .../ri/Equalizer/Methods/cdesc-Methods.ri | Bin 0 -> 491 bytes .../ri/Equalizer/Methods/eql%3f-i.ri | Bin 0 -> 613 bytes .../ri/Equalizer/cdesc-Equalizer.ri | Bin 0 -> 818 bytes .../ri/Equalizer/define_cmp_method-i.ri | Bin 0 -> 458 bytes .../ri/Equalizer/define_hash_method-i.ri | Bin 0 -> 459 bytes .../ri/Equalizer/define_inspect_method-i.ri | Bin 0 -> 464 bytes .../ri/Equalizer/define_methods-i.ri | Bin 0 -> 422 bytes .../ri/Equalizer/included-i.ri | Bin 0 -> 535 bytes .../doc/equalizer-0.0.9/ri/Equalizer/new-c.ri | Bin 0 -> 556 bytes .gems/doc/equalizer-0.0.9/ri/cache.ri | Bin 0 -> 555 bytes .../ri/page-CONTRIBUTING_md.ri | Bin 0 -> 1521 bytes .gems/doc/equalizer-0.0.9/ri/page-LICENSE.ri | Bin 0 -> 1458 bytes .../doc/equalizer-0.0.9/ri/page-README_md.ri | Bin 0 -> 3477 bytes .../ri/EmHttpSslPatch/cdesc-EmHttpSslPatch.ri | Bin 0 -> 544 bytes .../ri/EmHttpSslPatch/certificate_store-i.ri | Bin 0 -> 291 bytes .../faraday-0.9.0/ri/EmHttpSslPatch/host-i.ri | Bin 0 -> 265 bytes .../ssl_handshake_completed-i.ri | Bin 0 -> 303 bytes .../ri/EmHttpSslPatch/ssl_verify_peer-i.ri | Bin 0 -> 298 bytes .../ri/EmHttpSslPatch/verify_peer%3f-i.ri | Bin 0 -> 281 bytes .../ri/EventMachine/cdesc-EventMachine.ri | Bin 0 -> 398 bytes .../Faraday/Adapter/EMHttp/Manager/add-i.ri | Bin 0 -> 270 bytes .../Adapter/EMHttp/Manager/cdesc-Manager.ri | Bin 0 -> 768 bytes .../EMHttp/Manager/check_finished-i.ri | Bin 0 -> 286 bytes .../Faraday/Adapter/EMHttp/Manager/new-c.ri | Bin 0 -> 265 bytes .../EMHttp/Manager/perform_request-i.ri | Bin 0 -> 294 bytes .../Faraday/Adapter/EMHttp/Manager/reset-i.ri | Bin 0 -> 268 bytes .../Faraday/Adapter/EMHttp/Manager/run-i.ri | Bin 0 -> 264 bytes .../Adapter/EMHttp/Manager/running%3f-i.ri | Bin 0 -> 274 bytes .../Adapter/EMHttp/Options/cdesc-Options.ri | Bin 0 -> 697 bytes .../EMHttp/Options/configure_compression-i.ri | Bin 0 -> 313 bytes .../EMHttp/Options/configure_proxy-i.ri | Bin 0 -> 301 bytes .../EMHttp/Options/configure_socket-i.ri | Bin 0 -> 303 bytes .../Adapter/EMHttp/Options/configure_ssl-i.ri | Bin 0 -> 297 bytes .../EMHttp/Options/configure_timeout-i.ri | Bin 0 -> 305 bytes .../EMHttp/Options/connection_config-i.ri | Bin 0 -> 296 bytes .../Adapter/EMHttp/Options/read_body-i.ri | Bin 0 -> 280 bytes .../EMHttp/Options/request_config-i.ri | Bin 0 -> 290 bytes .../EMHttp/Options/request_options-i.ri | Bin 0 -> 292 bytes .../ri/Faraday/Adapter/EMHttp/call-i.ri | Bin 0 -> 259 bytes .../ri/Faraday/Adapter/EMHttp/cdesc-EMHttp.ri | Bin 0 -> 862 bytes .../Faraday/Adapter/EMHttp/error_message-i.ri | Bin 0 -> 280 bytes .../Faraday/Adapter/EMHttp/parallel%3f-i.ri | Bin 0 -> 269 bytes .../Adapter/EMHttp/perform_request-i.ri | Bin 0 -> 281 bytes .../EMHttp/perform_single_request-i.ri | Bin 0 -> 381 bytes .../Faraday/Adapter/EMHttp/raise_error-i.ri | Bin 0 -> 273 bytes .../EMHttp/setup_parallel_manager-c.ri | Bin 0 -> 306 bytes .../EMSynchrony/ParallelManager/add-i.ri | Bin 0 -> 465 bytes .../ParallelManager/cdesc-ParallelManager.ri | Bin 0 -> 604 bytes .../EMSynchrony/ParallelManager/perform-i.ri | Bin 0 -> 392 bytes .../EMSynchrony/ParallelManager/queue-i.ri | Bin 0 -> 368 bytes .../EMSynchrony/ParallelManager/run-i.ri | Bin 0 -> 452 bytes .../ri/Faraday/Adapter/EMSynchrony/call-i.ri | Bin 0 -> 274 bytes .../Adapter/EMSynchrony/cdesc-EMSynchrony.ri | Bin 0 -> 647 bytes .../EMSynchrony/setup_parallel_manager-c.ri | Bin 0 -> 320 bytes .../ri/Faraday/Adapter/Excon/call-i.ri | Bin 0 -> 255 bytes .../ri/Faraday/Adapter/Excon/cdesc-Excon.ri | Bin 0 -> 507 bytes .../ri/Faraday/Adapter/Excon/new-c.ri | Bin 0 -> 279 bytes .../ri/Faraday/Adapter/Excon/read_body-i.ri | Bin 0 -> 335 bytes .../ri/Faraday/Adapter/HTTPClient/call-i.ri | Bin 0 -> 270 bytes .../Adapter/HTTPClient/cdesc-HTTPClient.ri | Bin 0 -> 642 bytes .../ri/Faraday/Adapter/HTTPClient/client-i.ri | Bin 0 -> 271 bytes .../Adapter/HTTPClient/configure_proxy-i.ri | Bin 0 -> 294 bytes .../Adapter/HTTPClient/configure_socket-i.ri | Bin 0 -> 295 bytes .../Adapter/HTTPClient/configure_ssl-i.ri | Bin 0 -> 288 bytes .../HTTPClient/configure_timeouts-i.ri | Bin 0 -> 298 bytes .../Adapter/HTTPClient/ssl_verify_mode-i.ri | Bin 0 -> 292 bytes .../Adapter/NetHttp/OpenSSL/SSL/cdesc-SSL.ri | Bin 0 -> 425 bytes .../Adapter/NetHttp/OpenSSL/cdesc-OpenSSL.ri | Bin 0 -> 414 bytes .../ri/Faraday/Adapter/NetHttp/call-i.ri | Bin 0 -> 262 bytes .../Faraday/Adapter/NetHttp/cdesc-NetHttp.ri | Bin 0 -> 763 bytes .../Adapter/NetHttp/configure_ssl-i.ri | Bin 0 -> 286 bytes .../Adapter/NetHttp/create_request-i.ri | Bin 0 -> 282 bytes .../Adapter/NetHttp/net_http_connection-i.ri | Bin 0 -> 292 bytes .../Adapter/NetHttp/perform_request-i.ri | Bin 0 -> 290 bytes .../Adapter/NetHttp/ssl_cert_store-i.ri | Bin 0 -> 282 bytes .../Adapter/NetHttp/ssl_verify_mode-i.ri | Bin 0 -> 284 bytes .../cdesc-NetHttpPersistent.ri | Bin 0 -> 681 bytes .../NetHttpPersistent/configure_ssl-i.ri | Bin 0 -> 317 bytes .../net_http_connection-i.ri | Bin 0 -> 323 bytes .../NetHttpPersistent/perform_request-i.ri | Bin 0 -> 321 bytes .../proxy_uri;/cdesc-proxy_uri;.ri | Bin 0 -> 466 bytes .../Adapter/Parallelism/cdesc-Parallelism.ri | Bin 0 -> 632 bytes .../Adapter/Parallelism/inherited-i.ri | Bin 0 -> 277 bytes .../Parallelism/supports_parallel%3f-i.ri | Bin 0 -> 287 bytes .../Parallelism/supports_parallel-i.ri | Bin 0 -> 292 bytes .../Adapter/Patron/Request/cdesc-Request.ri | Bin 0 -> 410 bytes .../ri/Faraday/Adapter/Patron/call-i.ri | Bin 0 -> 258 bytes .../ri/Faraday/Adapter/Patron/cdesc-Patron.ri | Bin 0 -> 516 bytes .../Adapter/Patron/create_session-i.ri | Bin 0 -> 275 bytes .../ri/Faraday/Adapter/Patron/new-c.ri | Bin 0 -> 265 bytes .../ri/Faraday/Adapter/Rack/call-i.ri | Bin 0 -> 252 bytes .../ri/Faraday/Adapter/Rack/cdesc-Rack.ri | Bin 0 -> 1048 bytes .../Faraday/Adapter/Rack/execute_request-i.ri | Bin 0 -> 284 bytes .../ri/Faraday/Adapter/Rack/new-c.ri | Bin 0 -> 269 bytes .../Faraday/Adapter/Test/Stub/cdesc-Stub.ri | Bin 0 -> 598 bytes .../Adapter/Test/Stub/headers_match%3f-i.ri | Bin 0 -> 290 bytes .../Faraday/Adapter/Test/Stub/matches%3f-i.ri | Bin 0 -> 305 bytes .../ri/Faraday/Adapter/Test/Stub/new-c.ri | Bin 0 -> 280 bytes .../Adapter/Test/Stub/params_match%3f-i.ri | Bin 0 -> 287 bytes .../ri/Faraday/Adapter/Test/Stub/to_s-i.ri | Bin 0 -> 255 bytes .../Test/Stubs/NotFound/cdesc-NotFound.ri | Bin 0 -> 453 bytes .../Faraday/Adapter/Test/Stubs/cdesc-Stubs.ri | Bin 0 -> 683 bytes .../ri/Faraday/Adapter/Test/Stubs/delete-i.ri | Bin 0 -> 287 bytes .../Faraday/Adapter/Test/Stubs/empty%3f-i.ri | Bin 0 -> 261 bytes .../ri/Faraday/Adapter/Test/Stubs/get-i.ri | Bin 0 -> 281 bytes .../ri/Faraday/Adapter/Test/Stubs/head-i.ri | Bin 0 -> 283 bytes .../ri/Faraday/Adapter/Test/Stubs/match-i.ri | Bin 0 -> 294 bytes .../Adapter/Test/Stubs/matches%3f-i.ri | Bin 0 -> 294 bytes .../ri/Faraday/Adapter/Test/Stubs/new-c.ri | Bin 0 -> 266 bytes .../Faraday/Adapter/Test/Stubs/new_stub-i.ri | Bin 0 -> 320 bytes .../Faraday/Adapter/Test/Stubs/options-i.ri | Bin 0 -> 289 bytes .../ri/Faraday/Adapter/Test/Stubs/patch-i.ri | Bin 0 -> 295 bytes .../ri/Faraday/Adapter/Test/Stubs/post-i.ri | Bin 0 -> 293 bytes .../ri/Faraday/Adapter/Test/Stubs/put-i.ri | Bin 0 -> 291 bytes .../Test/Stubs/verify_stubbed_calls-i.ri | Bin 0 -> 390 bytes .../ri/Faraday/Adapter/Test/call-i.ri | Bin 0 -> 252 bytes .../ri/Faraday/Adapter/Test/cdesc-Test.ri | Bin 0 -> 912 bytes .../ri/Faraday/Adapter/Test/configure-i.ri | Bin 0 -> 270 bytes .../ri/Faraday/Adapter/Test/new-c.ri | Bin 0 -> 270 bytes .../ri/Faraday/Adapter/Test/stubs-i.ri | Bin 0 -> 259 bytes .../ri/Faraday/Adapter/Typhoeus/call-i.ri | Bin 0 -> 264 bytes .../Adapter/Typhoeus/cdesc-Typhoeus.ri | Bin 0 -> 733 bytes .../Adapter/Typhoeus/configure_proxy-i.ri | Bin 0 -> 291 bytes .../Adapter/Typhoeus/configure_socket-i.ri | Bin 0 -> 293 bytes .../Adapter/Typhoeus/configure_ssl-i.ri | Bin 0 -> 287 bytes .../Adapter/Typhoeus/configure_timeout-i.ri | Bin 0 -> 295 bytes .../Faraday/Adapter/Typhoeus/parallel%3f-i.ri | Bin 0 -> 274 bytes .../Adapter/Typhoeus/perform_request-i.ri | Bin 0 -> 286 bytes .../Faraday/Adapter/Typhoeus/read_body-i.ri | Bin 0 -> 344 bytes .../ri/Faraday/Adapter/Typhoeus/request-i.ri | Bin 0 -> 270 bytes .../Adapter/Typhoeus/request_options-i.ri | Bin 0 -> 286 bytes .../Typhoeus/setup_parallel_manager-c.ri | Bin 0 -> 310 bytes .../ri/Faraday/Adapter/call-i.ri | Bin 0 -> 244 bytes .../ri/Faraday/Adapter/cdesc-Adapter.ri | Bin 0 -> 1504 bytes .../ri/Faraday/Adapter/save_response-i.ri | Bin 0 -> 313 bytes .../AutoloadHelper/all_loaded_constants-i.ri | Bin 0 -> 502 bytes .../Faraday/AutoloadHelper/autoload_all-i.ri | Bin 0 -> 902 bytes .../AutoloadHelper/cdesc-AutoloadHelper.ri | Bin 0 -> 641 bytes .../load_autoloaded_constants-i.ri | Bin 0 -> 497 bytes .../ri/Faraday/ClientError/backtrace-i.ri | Bin 0 -> 257 bytes .../Faraday/ClientError/cdesc-ClientError.ri | Bin 0 -> 517 bytes .../ri/Faraday/ClientError/inspect-i.ri | Bin 0 -> 253 bytes .../ri/Faraday/ClientError/new-c.ri | Bin 0 -> 264 bytes .../ri/Faraday/ClientError/response-i.ri | Bin 0 -> 253 bytes .../Faraday/CompositeReadIO/advance_io-i.ri | Bin 0 -> 272 bytes .../CompositeReadIO/cdesc-CompositeReadIO.ri | Bin 0 -> 714 bytes .../ri/Faraday/CompositeReadIO/close-i.ri | Bin 0 -> 261 bytes .../Faraday/CompositeReadIO/current_io-i.ri | Bin 0 -> 272 bytes .../ensure_open_and_readable-i.ri | Bin 0 -> 299 bytes .../ri/Faraday/CompositeReadIO/length-i.ri | Bin 0 -> 263 bytes .../ri/Faraday/CompositeReadIO/new-c.ri | Bin 0 -> 264 bytes .../ri/Faraday/CompositeReadIO/read-i.ri | Bin 0 -> 386 bytes .../ri/Faraday/CompositeReadIO/rewind-i.ri | Bin 0 -> 263 bytes .../ri/Faraday/Connection/authorization-i.ri | Bin 0 -> 1003 bytes .../ri/Faraday/Connection/basic_auth-i.ri | Bin 0 -> 754 bytes .../Connection/build_exclusive_url-i.ri | Bin 0 -> 678 bytes .../ri/Faraday/Connection/build_request-i.ri | Bin 0 -> 429 bytes .../ri/Faraday/Connection/build_url-i.ri | Bin 0 -> 882 bytes .../ri/Faraday/Connection/builder-i.ri | 2 + .../ri/Faraday/Connection/cdesc-Connection.ri | Bin 0 -> 1725 bytes .../Connection/default_parallel_manager-i.ri | 2 + .../ri/Faraday/Connection/dup-i.ri | Bin 0 -> 416 bytes .../ri/Faraday/Connection/headers%3d-i.ri | Bin 0 -> 363 bytes .../ri/Faraday/Connection/headers-i.ri | 2 + .../ri/Faraday/Connection/in_parallel%3f-i.ri | Bin 0 -> 441 bytes .../ri/Faraday/Connection/in_parallel-i.ri | Bin 0 -> 578 bytes .../ri/Faraday/Connection/new-c.ri | Bin 0 -> 1138 bytes .../ri/Faraday/Connection/options-i.ri | 2 + .../Faraday/Connection/parallel_manager-i.ri | 2 + .../ri/Faraday/Connection/params%3d-i.ri | Bin 0 -> 359 bytes .../ri/Faraday/Connection/params-i.ri | 2 + .../ri/Faraday/Connection/path_prefix%3d-i.ri | Bin 0 -> 503 bytes .../ri/Faraday/Connection/proxy-i.ri | Bin 0 -> 343 bytes .../ri/Faraday/Connection/run_request-i.ri | Bin 0 -> 637 bytes .../Connection/set_authorization_header-i.ri | Bin 0 -> 308 bytes .../ri/Faraday/Connection/ssl-i.ri | 2 + .../ri/Faraday/Connection/token_auth-i.ri | Bin 0 -> 757 bytes .../ri/Faraday/Connection/url_prefix%3d-i.ri | Bin 0 -> 941 bytes .../ri/Faraday/Connection/url_prefix-i.ri | 2 + .../Connection/with_uri_credentials-i.ri | Bin 0 -> 426 bytes .../cdesc-ConnectionFailed.ri | Bin 0 -> 426 bytes .../cdesc-ConnectionOptions.ri | Bin 0 -> 568 bytes .../ConnectionOptions/new_builder-i.ri | Bin 0 -> 280 bytes .../ri/Faraday/Env/%5b%5d%3d-i.ri | Bin 0 -> 285 bytes .../faraday-0.9.0/ri/Faraday/Env/%5b%5d-i.ri | Bin 0 -> 276 bytes .../ri/Faraday/Env/Utils/cdesc-Utils.ri | Bin 0 -> 375 bytes .../faraday-0.9.0/ri/Faraday/Env/cdesc-Env.ri | Bin 0 -> 1415 bytes .../ri/Faraday/Env/clear_body-i.ri | Bin 0 -> 289 bytes .../ri/Faraday/Env/custom_members-i.ri | Bin 0 -> 299 bytes .../ri/Faraday/Env/in_member_set%3f-i.ri | Bin 0 -> 256 bytes .../faraday-0.9.0/ri/Faraday/Env/inspect-i.ri | Bin 0 -> 239 bytes .../ri/Faraday/Env/member_set-c.ri | Bin 0 -> 292 bytes .../ri/Faraday/Env/needs_body%3f-i.ri | Bin 0 -> 291 bytes .../ri/Faraday/Env/parallel%3f-i.ri | Bin 0 -> 287 bytes .../ri/Faraday/Env/parse_body%3f-i.ri | Bin 0 -> 291 bytes .../ri/Faraday/Env/success%3f-i.ri | Bin 0 -> 285 bytes .../ri/Faraday/Error/cdesc-Error.ri | Bin 0 -> 474 bytes .../cdesc-FlatParamsEncoder.ri | Bin 0 -> 613 bytes .../ri/Faraday/FlatParamsEncoder/decode-c.ri | Bin 0 -> 275 bytes .../ri/Faraday/FlatParamsEncoder/encode-c.ri | Bin 0 -> 276 bytes .../ri/Faraday/FlatParamsEncoder/escape-c.ri | Bin 0 -> 271 bytes .../Faraday/FlatParamsEncoder/unescape-c.ri | Bin 0 -> 275 bytes .../ri/Faraday/Middleware/cdesc-Middleware.ri | Bin 0 -> 585 bytes .../ri/Faraday/Middleware/dependency-c.ri | Bin 0 -> 394 bytes .../ri/Faraday/Middleware/inherited-c.ri | Bin 0 -> 269 bytes .../ri/Faraday/Middleware/load_error-c.ri | Bin 0 -> 262 bytes .../ri/Faraday/Middleware/loaded%3f-c.ri | Bin 0 -> 257 bytes .../ri/Faraday/Middleware/new-c.ri | Bin 0 -> 258 bytes .../cdesc-MiddlewareRegistry.ri | Bin 0 -> 686 bytes .../MiddlewareRegistry/fetch_middleware-i.ri | Bin 0 -> 283 bytes .../MiddlewareRegistry/load_middleware-i.ri | Bin 0 -> 281 bytes .../MiddlewareRegistry/lookup_middleware-i.ri | Bin 0 -> 796 bytes .../MiddlewareRegistry/middleware_mutex-i.ri | Bin 0 -> 286 bytes .../register_middleware-i.ri | Bin 0 -> 1229 bytes .../cdesc-MissingDependency.ri | Bin 0 -> 422 bytes .../cdesc-NestedParamsEncoder.ri | Bin 0 -> 619 bytes .../Faraday/NestedParamsEncoder/decode-c.ri | Bin 0 -> 279 bytes .../Faraday/NestedParamsEncoder/encode-c.ri | Bin 0 -> 280 bytes .../Faraday/NestedParamsEncoder/escape-c.ri | Bin 0 -> 275 bytes .../Faraday/NestedParamsEncoder/unescape-c.ri | Bin 0 -> 279 bytes .../ri/Faraday/Options/%5b%5d-i.ri | Bin 0 -> 240 bytes .../ri/Faraday/Options/attribute_options-c.ri | Bin 0 -> 314 bytes .../ri/Faraday/Options/cdesc-Options.ri | Bin 0 -> 1087 bytes .../ri/Faraday/Options/clear-i.ri | Bin 0 -> 287 bytes .../ri/Faraday/Options/delete-i.ri | Bin 0 -> 292 bytes .../ri/Faraday/Options/each-i.ri | Bin 0 -> 308 bytes .../ri/Faraday/Options/each_key-i.ri | Bin 0 -> 302 bytes .../ri/Faraday/Options/each_value-i.ri | Bin 0 -> 308 bytes .../ri/Faraday/Options/empty%3f-i.ri | Bin 0 -> 289 bytes .../ri/Faraday/Options/fetch-i.ri | Bin 0 -> 297 bytes .../ri/Faraday/Options/fetch_error_class-c.ri | Bin 0 -> 268 bytes .../ri/Faraday/Options/from-c.ri | Bin 0 -> 291 bytes .../ri/Faraday/Options/has_key%3f-i.ri | Bin 0 -> 252 bytes .../ri/Faraday/Options/has_value%3f-i.ri | Bin 0 -> 258 bytes .../ri/Faraday/Options/inherited-c.ri | Bin 0 -> 260 bytes .../ri/Faraday/Options/inspect-i.ri | Bin 0 -> 293 bytes .../ri/Faraday/Options/key%3f-i.ri | Bin 0 -> 320 bytes .../ri/Faraday/Options/keys-i.ri | Bin 0 -> 285 bytes .../ri/Faraday/Options/memoized-c.ri | Bin 0 -> 253 bytes .../Faraday/Options/memoized_attributes-c.ri | Bin 0 -> 272 bytes .../ri/Faraday/Options/merge%21-i.ri | Bin 0 -> 248 bytes .../ri/Faraday/Options/merge-i.ri | Bin 0 -> 292 bytes .../ri/Faraday/Options/options-c.ri | Bin 0 -> 301 bytes .../ri/Faraday/Options/options_for-c.ri | Bin 0 -> 305 bytes .../Faraday/Options/symbolized_key_set-i.ri | Bin 0 -> 269 bytes .../ri/Faraday/Options/to_hash-i.ri | Bin 0 -> 291 bytes .../ri/Faraday/Options/update-i.ri | Bin 0 -> 322 bytes .../ri/Faraday/Options/value%3f-i.ri | Bin 0 -> 328 bytes .../ri/Faraday/Options/values_at-i.ri | Bin 0 -> 300 bytes .../ParsingError/cdesc-ParsingError.ri | Bin 0 -> 418 bytes .../ProxyOptions/cdesc-ProxyOptions.ri | Bin 0 -> 514 bytes .../ri/Faraday/ProxyOptions/from-c.ri | Bin 0 -> 257 bytes .../ri/Faraday/RackBuilder/%3d%3d-i.ri | Bin 0 -> 255 bytes .../ri/Faraday/RackBuilder/%5b%5d-i.ri | Bin 0 -> 253 bytes .../Faraday/RackBuilder/Handler/%3d%3d-i.ri | Bin 0 -> 260 bytes .../ri/Faraday/RackBuilder/Handler/build-i.ri | Bin 0 -> 264 bytes .../RackBuilder/Handler/cdesc-Handler.ri | Bin 0 -> 704 bytes .../Faraday/RackBuilder/Handler/inspect-i.ri | Bin 0 -> 265 bytes .../ri/Faraday/RackBuilder/Handler/klass-i.ri | Bin 0 -> 261 bytes .../ri/Faraday/RackBuilder/Handler/name-i.ri | Bin 0 -> 270 bytes .../ri/Faraday/RackBuilder/Handler/new-c.ri | Bin 0 -> 278 bytes .../StackLocked/cdesc-StackLocked.ri | Bin 0 -> 544 bytes .../ri/Faraday/RackBuilder/adapter-i.ri | Bin 0 -> 278 bytes .../ri/Faraday/RackBuilder/app-i.ri | Bin 0 -> 653 bytes .../ri/Faraday/RackBuilder/assert_index-i.ri | Bin 0 -> 276 bytes .../ri/Faraday/RackBuilder/build-i.ri | Bin 0 -> 278 bytes .../ri/Faraday/RackBuilder/build_env-i.ri | Bin 0 -> 1244 bytes .../Faraday/RackBuilder/build_response-i.ri | Bin 0 -> 584 bytes .../Faraday/RackBuilder/cdesc-RackBuilder.ri | Bin 0 -> 1341 bytes .../ri/Faraday/RackBuilder/delete-i.ri | Bin 0 -> 265 bytes .../ri/Faraday/RackBuilder/dup-i.ri | Bin 0 -> 252 bytes .../ri/Faraday/RackBuilder/handlers-i.ri | Bin 0 -> 261 bytes .../ri/Faraday/RackBuilder/insert-i.ri | Bin 0 -> 409 bytes .../ri/Faraday/RackBuilder/insert_after-i.ri | Bin 0 -> 290 bytes .../ri/Faraday/RackBuilder/insert_before-i.ri | Bin 0 -> 292 bytes .../ri/Faraday/RackBuilder/lock%21-i.ri | Bin 0 -> 369 bytes .../ri/Faraday/RackBuilder/locked%3f-i.ri | Bin 0 -> 260 bytes .../ri/Faraday/RackBuilder/new-c.ri | Bin 0 -> 266 bytes .../Faraday/RackBuilder/raise_if_locked-i.ri | Bin 0 -> 277 bytes .../ri/Faraday/RackBuilder/request-i.ri | Bin 0 -> 278 bytes .../ri/Faraday/RackBuilder/response-i.ri | Bin 0 -> 280 bytes .../ri/Faraday/RackBuilder/swap-i.ri | Bin 0 -> 274 bytes .../ri/Faraday/RackBuilder/to_app-i.ri | Bin 0 -> 267 bytes .../ri/Faraday/RackBuilder/use-i.ri | Bin 0 -> 272 bytes .../ri/Faraday/RackBuilder/use_symbol-i.ri | Bin 0 -> 290 bytes .../ri/Faraday/Request/%5b%5d%3d-i.ri | Bin 0 -> 249 bytes .../ri/Faraday/Request/%5b%5d-i.ri | Bin 0 -> 240 bytes .../Request/Authorization/build_hash-c.ri | Bin 0 -> 345 bytes .../Faraday/Request/Authorization/call-i.ri | Bin 0 -> 323 bytes .../Authorization/cdesc-Authorization.ri | Bin 0 -> 667 bytes .../Faraday/Request/Authorization/header-c.ri | Bin 0 -> 336 bytes .../ri/Faraday/Request/Authorization/new-c.ri | Bin 0 -> 291 bytes .../cdesc-BasicAuthentication.ri | Bin 0 -> 548 bytes .../Request/BasicAuthentication/header-c.ri | Bin 0 -> 311 bytes .../Instrumentation/Options/cdesc-Options.ri | Bin 0 -> 580 bytes .../Instrumentation/Options/instrumenter-i.ri | Bin 0 -> 299 bytes .../Request/Instrumentation/Options/name-i.ri | Bin 0 -> 283 bytes .../Faraday/Request/Instrumentation/call-i.ri | Bin 0 -> 285 bytes .../Instrumentation/cdesc-Instrumentation.ri | Bin 0 -> 522 bytes .../Faraday/Request/Instrumentation/new-c.ri | Bin 0 -> 857 bytes .../ri/Faraday/Request/Multipart/call-i.ri | Bin 0 -> 267 bytes .../Request/Multipart/cdesc-Multipart.ri | Bin 0 -> 734 bytes .../Request/Multipart/create_multipart-i.ri | Bin 0 -> 299 bytes .../Request/Multipart/has_multipart%3f-i.ri | Bin 0 -> 287 bytes .../Request/Multipart/process_params-i.ri | Bin 0 -> 326 bytes .../Request/Multipart/process_request%3f-i.ri | Bin 0 -> 291 bytes .../Request/Retry/Options/backoff_factor-i.ri | Bin 0 -> 283 bytes .../Request/Retry/Options/cdesc-Options.ri | Bin 0 -> 673 bytes .../Request/Retry/Options/exceptions-i.ri | Bin 0 -> 275 bytes .../Faraday/Request/Retry/Options/from-c.ri | Bin 0 -> 269 bytes .../Request/Retry/Options/interval-i.ri | Bin 0 -> 271 bytes .../Retry/Options/interval_randomness-i.ri | Bin 0 -> 293 bytes .../ri/Faraday/Request/Retry/Options/max-i.ri | Bin 0 -> 261 bytes .../Retry/build_exception_matcher-i.ri | Bin 0 -> 575 bytes .../ri/Faraday/Request/Retry/call-i.ri | Bin 0 -> 255 bytes .../ri/Faraday/Request/Retry/cdesc-Retry.ri | Bin 0 -> 1465 bytes .../Request/Retry/matcher;/cdesc-matcher;.ri | Bin 0 -> 424 bytes .../ri/Faraday/Request/Retry/new-c.ri | Bin 0 -> 1122 bytes .../Faraday/Request/Retry/sleep_amount-i.ri | Bin 0 -> 275 bytes .../cdesc-TokenAuthentication.ri | Bin 0 -> 562 bytes .../Request/TokenAuthentication/header-c.ri | Bin 0 -> 320 bytes .../Request/TokenAuthentication/new-c.ri | Bin 0 -> 319 bytes .../ri/Faraday/Request/UrlEncoded/call-i.ri | Bin 0 -> 271 bytes .../Request/UrlEncoded/cdesc-UrlEncoded.ri | Bin 0 -> 731 bytes .../UrlEncoded/match_content_type-i.ri | Bin 0 -> 309 bytes .../Faraday/Request/UrlEncoded/mime_type-c.ri | Bin 0 -> 287 bytes .../UrlEncoded/process_request%3f-i.ri | Bin 0 -> 295 bytes .../Request/UrlEncoded/request_type-i.ri | Bin 0 -> 287 bytes .../ri/Faraday/Request/cdesc-Request.ri | Bin 0 -> 1536 bytes .../ri/Faraday/Request/create-c.ri | Bin 0 -> 273 bytes .../ri/Faraday/Request/headers%3d-i.ri | Bin 0 -> 357 bytes .../ri/Faraday/Request/params%3d-i.ri | Bin 0 -> 346 bytes .../ri/Faraday/Request/to_env-i.ri | Bin 0 -> 1216 bytes .../faraday-0.9.0/ri/Faraday/Request/url-i.ri | Bin 0 -> 257 bytes .../ri/Faraday/RequestOptions/%5b%5d%3d-i.ri | Bin 0 -> 263 bytes .../RequestOptions/cdesc-RequestOptions.ri | Bin 0 -> 540 bytes .../cdesc-ResourceNotFound.ri | Bin 0 -> 426 bytes .../ri/Faraday/Response/Logger/call-i.ri | Bin 0 -> 260 bytes .../Faraday/Response/Logger/cdesc-Logger.ri | Bin 0 -> 581 bytes .../Faraday/Response/Logger/dump_headers-i.ri | Bin 0 -> 281 bytes .../ri/Faraday/Response/Logger/new-c.ri | Bin 0 -> 273 bytes .../Faraday/Response/Logger/on_complete-i.ri | Bin 0 -> 274 bytes .../ri/Faraday/Response/Middleware/call-i.ri | Bin 0 -> 261 bytes .../Response/Middleware/cdesc-Middleware.ri | Bin 0 -> 574 bytes .../Response/Middleware/on_complete-i.ri | Bin 0 -> 428 bytes .../Response/RaiseError/cdesc-RaiseError.ri | Bin 0 -> 681 bytes .../Response/RaiseError/on_complete-i.ri | Bin 0 -> 287 bytes .../Response/RaiseError/response_values-i.ri | Bin 0 -> 295 bytes .../ri/Faraday/Response/apply_request-i.ri | Bin 0 -> 462 bytes .../ri/Faraday/Response/body-i.ri | Bin 0 -> 244 bytes .../ri/Faraday/Response/cdesc-Response.ri | Bin 0 -> 937 bytes .../ri/Faraday/Response/env-i.ri | Bin 0 -> 240 bytes .../ri/Faraday/Response/finish-i.ri | Bin 0 -> 251 bytes .../ri/Faraday/Response/finished%3f-i.ri | Bin 0 -> 254 bytes .../ri/Faraday/Response/headers-i.ri | Bin 0 -> 250 bytes .../ri/Faraday/Response/marshal_dump-i.ri | Bin 0 -> 349 bytes .../ri/Faraday/Response/marshal_load-i.ri | Bin 0 -> 263 bytes .../ri/Faraday/Response/new-c.ri | Bin 0 -> 252 bytes .../ri/Faraday/Response/on_complete-i.ri | Bin 0 -> 267 bytes .../ri/Faraday/Response/status-i.ri | Bin 0 -> 248 bytes .../ri/Faraday/Response/success%3f-i.ri | Bin 0 -> 252 bytes .../ri/Faraday/SSLError/cdesc-SSLError.ri | Bin 0 -> 410 bytes .../ri/Faraday/SSLOptions/cdesc-SSLOptions.ri | Bin 0 -> 612 bytes .../ri/Faraday/SSLOptions/disable%3f-i.ri | Bin 0 -> 255 bytes .../ri/Faraday/SSLOptions/verify%3f-i.ri | Bin 0 -> 253 bytes .../TimeoutError/cdesc-TimeoutError.ri | Bin 0 -> 457 bytes .../ri/Faraday/TimeoutError/new-c.ri | Bin 0 -> 256 bytes .../ri/Faraday/Utils/Headers/%5b%5d%3d-i.ri | Bin 0 -> 248 bytes .../ri/Faraday/Utils/Headers/%5b%5d-i.ri | Bin 0 -> 243 bytes .../ri/Faraday/Utils/Headers/cdesc-Headers.ri | Bin 0 -> 926 bytes .../ri/Faraday/Utils/Headers/delete-i.ri | Bin 0 -> 251 bytes .../ri/Faraday/Utils/Headers/fetch-i.ri | Bin 0 -> 264 bytes .../ri/Faraday/Utils/Headers/from-c.ri | Bin 0 -> 252 bytes .../ri/Faraday/Utils/Headers/has_key%3f-i.ri | Bin 0 -> 255 bytes .../ri/Faraday/Utils/Headers/include%3f-i.ri | Bin 0 -> 346 bytes .../ri/Faraday/Utils/Headers/key%3f-i.ri | Bin 0 -> 247 bytes .../ri/Faraday/Utils/Headers/member%3f-i.ri | Bin 0 -> 253 bytes .../ri/Faraday/Utils/Headers/merge%21-i.ri | Bin 0 -> 285 bytes .../ri/Faraday/Utils/Headers/merge-i.ri | Bin 0 -> 253 bytes .../ri/Faraday/Utils/Headers/new-c.ri | Bin 0 -> 255 bytes .../ri/Faraday/Utils/Headers/parse-i.ri | Bin 0 -> 261 bytes .../ri/Faraday/Utils/Headers/replace-i.ri | Bin 0 -> 257 bytes .../ri/Faraday/Utils/Headers/to_hash-i.ri | Bin 0 -> 252 bytes .../ri/Faraday/Utils/Headers/update-i.ri | Bin 0 -> 255 bytes .../Faraday/Utils/ParamsHash/%5b%5d%3d-i.ri | Bin 0 -> 260 bytes .../ri/Faraday/Utils/ParamsHash/%5b%5d-i.ri | Bin 0 -> 251 bytes .../Utils/ParamsHash/cdesc-ParamsHash.ri | Bin 0 -> 747 bytes .../Faraday/Utils/ParamsHash/convert_key-i.ri | Bin 0 -> 270 bytes .../ri/Faraday/Utils/ParamsHash/delete-i.ri | Bin 0 -> 259 bytes .../Faraday/Utils/ParamsHash/has_key%3f-i.ri | Bin 0 -> 263 bytes .../Faraday/Utils/ParamsHash/include%3f-i.ri | Bin 0 -> 354 bytes .../ri/Faraday/Utils/ParamsHash/key%3f-i.ri | Bin 0 -> 255 bytes .../Faraday/Utils/ParamsHash/member%3f-i.ri | Bin 0 -> 261 bytes .../ri/Faraday/Utils/ParamsHash/merge%21-i.ri | Bin 0 -> 262 bytes .../ri/Faraday/Utils/ParamsHash/merge-i.ri | Bin 0 -> 260 bytes .../Faraday/Utils/ParamsHash/merge_query-i.ri | Bin 0 -> 286 bytes .../ri/Faraday/Utils/ParamsHash/replace-i.ri | Bin 0 -> 263 bytes .../ri/Faraday/Utils/ParamsHash/to_query-i.ri | Bin 0 -> 273 bytes .../ri/Faraday/Utils/ParamsHash/update-i.ri | Bin 0 -> 292 bytes .../faraday-0.9.0/ri/Faraday/Utils/URI-i.ri | Bin 0 -> 422 bytes .../ri/Faraday/Utils/build_nested_query-i.ri | Bin 0 -> 270 bytes .../ri/Faraday/Utils/build_query-i.ri | Bin 0 -> 256 bytes .../ri/Faraday/Utils/cdesc-Utils.ri | Bin 0 -> 991 bytes .../ri/Faraday/Utils/deep_merge%21-i.ri | Bin 0 -> 321 bytes .../ri/Faraday/Utils/deep_merge-i.ri | Bin 0 -> 318 bytes .../Faraday/Utils/default_params_encoder-c.ri | Bin 0 -> 271 bytes .../Faraday/Utils/default_params_encoder-i.ri | Bin 0 -> 272 bytes .../Faraday/Utils/default_uri_parser%3d-i.ri | Bin 0 -> 272 bytes .../ri/Faraday/Utils/default_uri_parser-i.ri | Bin 0 -> 264 bytes .../ri/Faraday/Utils/escape-i.ri | Bin 0 -> 241 bytes .../ri/Faraday/Utils/normalize_params-i.ri | Bin 0 -> 335 bytes .../ri/Faraday/Utils/normalize_path-i.ri | Bin 0 -> 377 bytes .../ri/Faraday/Utils/parse_nested_query-i.ri | Bin 0 -> 269 bytes .../ri/Faraday/Utils/parse_query-i.ri | Bin 0 -> 310 bytes .../ri/Faraday/Utils/sort_query_params-i.ri | Bin 0 -> 270 bytes .../ri/Faraday/Utils/unescape-i.ri | Bin 0 -> 245 bytes .../faraday-0.9.0/ri/Faraday/cdesc-Faraday.ri | Bin 0 -> 3324 bytes .../ri/Faraday/const_missing-c.ri | Bin 0 -> 248 bytes .../ri/Faraday/default_adapter%3d-c.ri | Bin 0 -> 444 bytes .../ri/Faraday/default_adapter-c.ri | 2 + .../ri/Faraday/default_connection-c.ri | Bin 0 -> 501 bytes .../Faraday/default_connection_options-c.ri | 2 + .../faraday-0.9.0/ri/Faraday/lib_path-c.ri | 2 + .../ri/Faraday/method_missing-c.ri | Bin 0 -> 389 bytes .gems/doc/faraday-0.9.0/ri/Faraday/new-c.ri | Bin 0 -> 1362 bytes .../faraday-0.9.0/ri/Faraday/require_lib-c.ri | Bin 0 -> 245 bytes .../ri/Faraday/require_libs-c.ri | Bin 0 -> 502 bytes .../faraday-0.9.0/ri/Faraday/root_path-c.ri | 2 + .../faraday-0.9.0/ri/Object/cdesc-Object.ri | Bin 0 -> 502 bytes .gems/doc/faraday-0.9.0/ri/Object/tap-i.ri | Bin 0 -> 838 bytes .gems/doc/faraday-0.9.0/ri/cache.ri | Bin 0 -> 13317 bytes .../doc/http-0.6.2/ri/Base64/cdesc-Base64.ri | Bin 0 -> 353 bytes .../BasicAuth/cdesc-BasicAuth.ri | Bin 0 -> 638 bytes .../AuthorizationHeader/BasicAuth/new-c.ri | Bin 0 -> 413 bytes .../BearerToken/cdesc-BearerToken.ri | Bin 0 -> 738 bytes .../AuthorizationHeader/BearerToken/new-c.ri | Bin 0 -> 443 bytes .../ri/HTTP/AuthorizationHeader/build-c.ri | Bin 0 -> 463 bytes .../cdesc-AuthorizationHeader.ri | Bin 0 -> 690 bytes .../ri/HTTP/AuthorizationHeader/register-c.ri | Bin 0 -> 444 bytes .../http-0.6.2/ri/HTTP/Chainable/accept-i.ri | Bin 0 -> 317 bytes .../http-0.6.2/ri/HTTP/Chainable/auth-i.ri | Bin 0 -> 335 bytes .../http-0.6.2/ri/HTTP/Chainable/branch-i.ri | Bin 0 -> 254 bytes .../ri/HTTP/Chainable/cdesc-Chainable.ri | Bin 0 -> 907 bytes .../http-0.6.2/ri/HTTP/Chainable/connect-i.ri | Bin 0 -> 341 bytes .../HTTP/Chainable/default_callbacks%3d-i.ri | Bin 0 -> 279 bytes .../ri/HTTP/Chainable/default_callbacks-i.ri | Bin 0 -> 268 bytes .../ri/HTTP/Chainable/default_headers%3d-i.ri | Bin 0 -> 273 bytes .../ri/HTTP/Chainable/default_headers-i.ri | Bin 0 -> 264 bytes .../ri/HTTP/Chainable/default_options%3d-i.ri | Bin 0 -> 270 bytes .../ri/HTTP/Chainable/default_options-i.ri | Bin 0 -> 264 bytes .../http-0.6.2/ri/HTTP/Chainable/delete-i.ri | Bin 0 -> 318 bytes .../http-0.6.2/ri/HTTP/Chainable/follow-i.ri | 3 + .../doc/http-0.6.2/ri/HTTP/Chainable/get-i.ri | Bin 0 -> 309 bytes .../http-0.6.2/ri/HTTP/Chainable/head-i.ri | Bin 0 -> 329 bytes .../http-0.6.2/ri/HTTP/Chainable/options-i.ri | Bin 0 -> 348 bytes .../http-0.6.2/ri/HTTP/Chainable/patch-i.ri | Bin 0 -> 340 bytes .../http-0.6.2/ri/HTTP/Chainable/post-i.ri | Bin 0 -> 315 bytes .../doc/http-0.6.2/ri/HTTP/Chainable/put-i.ri | Bin 0 -> 312 bytes .../http-0.6.2/ri/HTTP/Chainable/request-i.ri | Bin 0 -> 349 bytes .../http-0.6.2/ri/HTTP/Chainable/stream-i.ri | Bin 0 -> 316 bytes .../http-0.6.2/ri/HTTP/Chainable/through-i.ri | Bin 0 -> 254 bytes .../http-0.6.2/ri/HTTP/Chainable/trace-i.ri | Bin 0 -> 334 bytes .../doc/http-0.6.2/ri/HTTP/Chainable/via-i.ri | Bin 0 -> 351 bytes .../http-0.6.2/ri/HTTP/Chainable/with-i.ri | Bin 0 -> 249 bytes .../ri/HTTP/Chainable/with_follow-i.ri | Bin 0 -> 337 bytes .../ri/HTTP/Chainable/with_headers-i.ri | Bin 0 -> 368 bytes .../http-0.6.2/ri/HTTP/Client/cdesc-Client.ri | Bin 0 -> 897 bytes .../ri/HTTP/Client/default_options-i.ri | Bin 0 -> 249 bytes .../ri/HTTP/Client/finish_response-i.ri | Bin 0 -> 346 bytes .../ri/HTTP/Client/make_request_body-i.ri | Bin 0 -> 348 bytes .../ri/HTTP/Client/make_request_uri-i.ri | Bin 0 -> 336 bytes .gems/doc/http-0.6.2/ri/HTTP/Client/new-c.ri | Bin 0 -> 251 bytes .../http-0.6.2/ri/HTTP/Client/perform-i.ri | Bin 0 -> 329 bytes .../http-0.6.2/ri/HTTP/Client/read_more-i.ri | Bin 0 -> 317 bytes .../ri/HTTP/Client/readpartial-i.ri | Bin 0 -> 326 bytes .../http-0.6.2/ri/HTTP/Client/request-i.ri | Bin 0 -> 316 bytes .../http-0.6.2/ri/HTTP/Client/start_tls-i.ri | Bin 0 -> 321 bytes .../http-0.6.2/ri/HTTP/Error/cdesc-Error.ri | Bin 0 -> 440 bytes .../ri/HTTP/Headers/Mixin/cdesc-Mixin.ri | Bin 0 -> 491 bytes .../ri/HTTP/Headers/Mixin/headers-i.ri | Bin 0 -> 257 bytes .../ri/HTTP/Headers/cdesc-Headers.ri | Bin 0 -> 749 bytes .../http-0.6.2/ri/HTTP/MimeType/%5b%5d-c.ri | Bin 0 -> 446 bytes .../ri/HTTP/MimeType/Adapter/cdesc-Adapter.ri | Bin 0 -> 597 bytes .../ri/HTTP/MimeType/JSON/cdesc-JSON.ri | Bin 0 -> 564 bytes .../ri/HTTP/MimeType/JSON/decode-i.ri | Bin 0 -> 303 bytes .../ri/HTTP/MimeType/JSON/encode-i.ri | Bin 0 -> 313 bytes .../ri/HTTP/MimeType/cdesc-MimeType.ri | Bin 0 -> 660 bytes .../ri/HTTP/MimeType/normalize-c.ri | Bin 0 -> 415 bytes .../ri/HTTP/MimeType/register_adapter-c.ri | Bin 0 -> 849 bytes .../ri/HTTP/MimeType/register_alias-c.ri | Bin 0 -> 590 bytes .../http-0.6.2/ri/HTTP/Options/%5b%5d-i.ri | Bin 0 -> 237 bytes .../ri/HTTP/Options/OpenSSL/SSL/cdesc-SSL.ri | Bin 0 -> 389 bytes .../ri/HTTP/Options/OpenSSL/cdesc-OpenSSL.ri | Bin 0 -> 378 bytes .../ri/HTTP/Options/argument_error%21-i.ri | Bin 0 -> 265 bytes .../doc/http-0.6.2/ri/HTTP/Options/body-i.ri | 2 + .../ri/HTTP/Options/cdesc-Options.ri | Bin 0 -> 961 bytes .../ri/HTTP/Options/default_socket_class-c.ri | Bin 0 -> 264 bytes .../Options/default_ssl_socket_class-c.ri | Bin 0 -> 272 bytes .gems/doc/http-0.6.2/ri/HTTP/Options/dup-i.ri | Bin 0 -> 245 bytes .../http-0.6.2/ri/HTTP/Options/follow-i.ri | 2 + .../doc/http-0.6.2/ri/HTTP/Options/form-i.ri | 2 + .../http-0.6.2/ri/HTTP/Options/headers-i.ri | 2 + .../doc/http-0.6.2/ri/HTTP/Options/json-i.ri | 2 + .../doc/http-0.6.2/ri/HTTP/Options/merge-i.ri | Bin 0 -> 242 bytes .gems/doc/http-0.6.2/ri/HTTP/Options/new-c.ri | Bin 0 -> 246 bytes .../http-0.6.2/ri/HTTP/Options/params-i.ri | 2 + .../doc/http-0.6.2/ri/HTTP/Options/proxy-i.ri | 3 + .../http-0.6.2/ri/HTTP/Options/response-i.ri | 2 + .../ri/HTTP/Options/socket_class-i.ri | 2 + .../ri/HTTP/Options/ssl_context-i.ri | 2 + .../ri/HTTP/Options/ssl_socket_class-i.ri | 2 + .../http-0.6.2/ri/HTTP/Options/to_hash-i.ri | Bin 0 -> 241 bytes .../ri/HTTP/Options/with_headers-i.ri | Bin 0 -> 258 bytes .../cdesc-EndlessRedirectError.ri | Bin 0 -> 568 bytes .../cdesc-TooManyRedirectsError.ri | Bin 0 -> 542 bytes .../ri/HTTP/Redirector/cdesc-Redirector.ri | Bin 0 -> 598 bytes .../cdesc-UnsupportedMethodError.ri | Bin 0 -> 519 bytes .../cdesc-UnsupportedSchemeError.ri | Bin 0 -> 526 bytes .../Request/Writer/add_body_type_headers-i.ri | Bin 0 -> 411 bytes .../ri/HTTP/Request/Writer/add_headers-i.ri | Bin 0 -> 358 bytes .../ri/HTTP/Request/Writer/cdesc-Writer.ri | Bin 0 -> 952 bytes .../ri/HTTP/Request/Writer/join_headers-i.ri | Bin 0 -> 406 bytes .../ri/HTTP/Request/Writer/new-c.ri | Bin 0 -> 282 bytes .../Request/Writer/send_request_body-i.ri | Bin 0 -> 275 bytes .../Request/Writer/send_request_header-i.ri | Bin 0 -> 279 bytes .../ri/HTTP/Request/Writer/stream-i.ri | Bin 0 -> 321 bytes .../Request/Writer/validate_body_type%21-i.ri | Bin 0 -> 280 bytes .../ri/HTTP/Request/__method__-i.ri | Bin 0 -> 388 bytes .../doc/http-0.6.2/ri/HTTP/Request/body-i.ri | Bin 0 -> 230 bytes .../ri/HTTP/Request/cdesc-Request.ri | Bin 0 -> 1233 bytes .../http-0.6.2/ri/HTTP/Request/method-i.ri | 3 + .../doc/http-0.6.2/ri/HTTP/Request/proxy-i.ri | Bin 0 -> 232 bytes .../http-0.6.2/ri/HTTP/Request/scheme-i.ri | 2 + .gems/doc/http-0.6.2/ri/HTTP/Request/uri-i.ri | 2 + .../doc/http-0.6.2/ri/HTTP/Request/verb-i.ri | 2 + .../http-0.6.2/ri/HTTP/Request/version-i.ri | Bin 0 -> 236 bytes .../HTTP/RequestError/cdesc-RequestError.ri | Bin 0 -> 460 bytes .../ri/HTTP/Response/Body/cdesc-Body.ri | Bin 0 -> 661 bytes .../ri/HTTP/Response/Body/each-i.ri | Bin 0 -> 334 bytes .../http-0.6.2/ri/HTTP/Response/Body/new-c.ri | Bin 0 -> 250 bytes .../ri/HTTP/Response/Body/readpartial-i.ri | Bin 0 -> 400 bytes .../ri/HTTP/Response/Parser/%3c%3c-i.ri | Bin 0 -> 251 bytes .../ri/HTTP/Response/Parser/add-i.ri | Bin 0 -> 279 bytes .../ri/HTTP/Response/Parser/cdesc-Parser.ri | Bin 0 -> 708 bytes .../ri/HTTP/Response/Parser/chunk-i.ri | Bin 0 -> 253 bytes .../ri/HTTP/Response/Parser/finished%3f-i.ri | Bin 0 -> 261 bytes .../ri/HTTP/Response/Parser/headers%3f-i.ri | Bin 0 -> 259 bytes .../ri/HTTP/Response/Parser/headers-i.ri | Bin 0 -> 262 bytes .../ri/HTTP/Response/Parser/http_version-i.ri | Bin 0 -> 267 bytes .../ri/HTTP/Response/Parser/new-c.ri | Bin 0 -> 250 bytes .../ri/HTTP/Response/Parser/on_body-i.ri | Bin 0 -> 262 bytes .../Response/Parser/on_headers_complete-i.ri | Bin 0 -> 348 bytes .../Response/Parser/on_message_complete-i.ri | Bin 0 -> 281 bytes .../ri/HTTP/Response/Parser/reset-i.ri | Bin 0 -> 253 bytes .../ri/HTTP/Response/Parser/status_code-i.ri | Bin 0 -> 265 bytes .../doc/http-0.6.2/ri/HTTP/Response/body-i.ri | Bin 0 -> 233 bytes .../ri/HTTP/Response/cdesc-Response.ri | Bin 0 -> 1139 bytes .../http-0.6.2/ri/HTTP/Response/charset-i.ri | Bin 0 -> 339 bytes .../doc/http-0.6.2/ri/HTTP/Response/code-i.ri | Bin 0 -> 233 bytes .../ri/HTTP/Response/content_type-i.ri | Bin 0 -> 353 bytes .../http-0.6.2/ri/HTTP/Response/flush-i.ri | Bin 0 -> 317 bytes .../http-0.6.2/ri/HTTP/Response/inspect-i.ri | Bin 0 -> 300 bytes .../ri/HTTP/Response/mime_type-i.ri | Bin 0 -> 345 bytes .../doc/http-0.6.2/ri/HTTP/Response/new-c.ri | Bin 0 -> 278 bytes .../http-0.6.2/ri/HTTP/Response/parse-i.ri | Bin 0 -> 591 bytes .../http-0.6.2/ri/HTTP/Response/reason-i.ri | Bin 0 -> 323 bytes .../http-0.6.2/ri/HTTP/Response/status-i.ri | Bin 0 -> 237 bytes .../ri/HTTP/Response/status_code-i.ri | Bin 0 -> 247 bytes .../ri/HTTP/Response/stream%21-i.ri | Bin 0 -> 334 bytes .../doc/http-0.6.2/ri/HTTP/Response/to_a-i.ri | Bin 0 -> 328 bytes .../doc/http-0.6.2/ri/HTTP/Response/to_s-i.ri | Bin 0 -> 389 bytes .../http-0.6.2/ri/HTTP/Response/to_str-i.ri | Bin 0 -> 272 bytes .../doc/http-0.6.2/ri/HTTP/Response/uri-i.ri | Bin 0 -> 231 bytes .../HTTP/ResponseError/cdesc-ResponseError.ri | Bin 0 -> 463 bytes .../ri/HTTP/StateError/cdesc-StateError.ri | Bin 0 -> 496 bytes .gems/doc/http-0.6.2/ri/HTTP/cdesc-HTTP.ri | Bin 0 -> 1550 bytes .../doc/http-0.6.2/ri/Object/cdesc-Object.ri | Bin 0 -> 429 bytes .gems/doc/http-0.6.2/ri/URI/cdesc-URI.ri | Bin 0 -> 868 bytes .../http-0.6.2/ri/URI/decode_www_form-c.ri | Bin 0 -> 1204 bytes .../ri/URI/decode_www_form_component-c.ri | Bin 0 -> 489 bytes .../http-0.6.2/ri/URI/encode_www_form-c.ri | Bin 0 -> 1589 bytes .../ri/URI/encode_www_form_component-c.ri | Bin 0 -> 737 bytes .gems/doc/http-0.6.2/ri/cache.ri | Bin 0 -> 5139 bytes .../ri/HTTP/Parser/cdesc-Parser.ri | Bin 0 -> 491 bytes .../Parser/default_header_value_type%3d-c.ri | Bin 0 -> 280 bytes .../Parser/default_header_value_type-c.ri | Bin 0 -> 270 bytes .../ri/HTTP/cdesc-HTTP.ri | Bin 0 -> 341 bytes .../ri/Object/cdesc-Object.ri | Bin 0 -> 436 bytes .gems/doc/http_parser.rb-0.6.0/ri/cache.ri | Bin 0 -> 478 bytes .../InstanceMethods/cdesc-InstanceMethods.ri | Bin 0 -> 603 bytes .../ri/Memoizable/InstanceMethods/freeze-i.ri | Bin 0 -> 526 bytes .../Memoizable/InstanceMethods/memoize-i.ri | Bin 0 -> 626 bytes .../memoized_method_cache-i.ri | Bin 0 -> 458 bytes .../ri/Memoizable/Memory/%5b%5d%3d-i.ri | Bin 0 -> 471 bytes .../ri/Memoizable/Memory/%5b%5d-i.ri | Bin 0 -> 430 bytes .../ri/Memoizable/Memory/cdesc-Memory.ri | Bin 0 -> 615 bytes .../ri/Memoizable/Memory/fetch-i.ri | Bin 0 -> 549 bytes .../ri/Memoizable/Memory/key%3f-i.ri | Bin 0 -> 448 bytes .../ri/Memoizable/Memory/marshal_dump-i.ri | Bin 0 -> 516 bytes .../ri/Memoizable/Memory/marshal_load-i.ri | Bin 0 -> 560 bytes .../ri/Memoizable/Memory/new-c.ri | Bin 0 -> 471 bytes .../cdesc-BlockNotAllowedError.ri | Bin 0 -> 613 bytes .../BlockNotAllowedError/new-c.ri | Bin 0 -> 517 bytes .../cdesc-InvalidArityError.ri | Bin 0 -> 596 bytes .../MethodBuilder/InvalidArityError/new-c.ri | Bin 0 -> 545 bytes .../MethodBuilder/assert_arity-i.ri | Bin 0 -> 529 bytes .../ri/Memoizable/MethodBuilder/call-i.ri | Bin 0 -> 539 bytes .../MethodBuilder/cdesc-MethodBuilder.ri | Bin 0 -> 732 bytes .../MethodBuilder/create_memoized_method-i.ri | Bin 0 -> 459 bytes .../ri/Memoizable/MethodBuilder/new-c.ri | Bin 0 -> 580 bytes .../MethodBuilder/original_method-i.ri | Bin 0 -> 458 bytes .../MethodBuilder/remove_original_method-i.ri | Bin 0 -> 457 bytes .../MethodBuilder/set_method_visibility-i.ri | Bin 0 -> 492 bytes .../Memoizable/MethodBuilder/visibility-i.ri | Bin 0 -> 445 bytes .../ModuleMethods/cdesc-ModuleMethods.ri | Bin 0 -> 736 bytes .../ri/Memoizable/ModuleMethods/freezer-i.ri | Bin 0 -> 424 bytes .../ri/Memoizable/ModuleMethods/included-i.ri | Bin 0 -> 567 bytes .../ri/Memoizable/ModuleMethods/memoize-i.ri | Bin 0 -> 604 bytes .../ModuleMethods/memoize_method-i.ri | Bin 0 -> 565 bytes .../Memoizable/ModuleMethods/memoized%3f-i.ri | Bin 0 -> 797 bytes .../ModuleMethods/memoized_methods-i.ri | Bin 0 -> 468 bytes .../unmemoized_instance_method-i.ri | Bin 0 -> 868 bytes .../ri/Memoizable/cdesc-Memoizable.ri | Bin 0 -> 1020 bytes .../ri/Memoizable/included-c.ri | Bin 0 -> 541 bytes .gems/doc/memoizable-0.4.2/ri/cache.ri | Bin 0 -> 1465 bytes .../ri/page-CONTRIBUTING_md.ri | Bin 0 -> 1521 bytes .../memoizable-0.4.2/ri/page-LICENSE_md.ri | Bin 0 -> 1309 bytes .../doc/memoizable-0.4.2/ri/page-README_md.ri | Bin 0 -> 4208 bytes .../ri/CompositeReadIO/advance_io-i.ri | Bin 0 -> 258 bytes .../CompositeReadIO/cdesc-CompositeReadIO.ri | Bin 0 -> 869 bytes .../ri/CompositeReadIO/current_io-i.ri | Bin 0 -> 258 bytes .../ri/CompositeReadIO/new-c.ri | Bin 0 -> 412 bytes .../ri/CompositeReadIO/read-i.ri | Bin 0 -> 372 bytes .../ri/CompositeReadIO/rewind-i.ri | Bin 0 -> 249 bytes .../ri/MultipartPost/cdesc-MultipartPost.ri | Bin 0 -> 459 bytes .../ri/Multipartable/cdesc-Multipartable.ri | Bin 0 -> 515 bytes .../ri/Multipartable/new-c.ri | Bin 0 -> 295 bytes .../HTTP/Post/Multipart/cdesc-Multipart.ri | Bin 0 -> 486 bytes .../ri/Net/HTTP/Post/cdesc-Post.ri | Bin 0 -> 386 bytes .../Net/HTTP/Put/Multipart/cdesc-Multipart.ri | Bin 0 -> 484 bytes .../ri/Net/HTTP/Put/cdesc-Put.ri | Bin 0 -> 399 bytes .../ri/Net/HTTP/cdesc-HTTP.ri | Bin 0 -> 375 bytes .../multipart-post-2.0.0/ri/Net/cdesc-Net.ri | Bin 0 -> 337 bytes .../Parts/EpiloguePart/cdesc-EpiloguePart.ri | Bin 0 -> 535 bytes .../ri/Parts/EpiloguePart/new-c.ri | Bin 0 -> 246 bytes .../ri/Parts/FilePart/build_head-i.ri | Bin 0 -> 311 bytes .../ri/Parts/FilePart/cdesc-FilePart.ri | Bin 0 -> 576 bytes .../ri/Parts/FilePart/length-i.ri | Bin 0 -> 231 bytes .../ri/Parts/FilePart/new-c.ri | Bin 0 -> 262 bytes .../ri/Parts/ParamPart/build_part-i.ri | Bin 0 -> 280 bytes .../ri/Parts/ParamPart/cdesc-ParamPart.ri | Bin 0 -> 485 bytes .../ri/Parts/ParamPart/length-i.ri | Bin 0 -> 237 bytes .../ri/Parts/ParamPart/new-c.ri | Bin 0 -> 267 bytes .../ri/Parts/Part/cdesc-Part.ri | Bin 0 -> 350 bytes .../ri/Parts/cdesc-Parts.ri | Bin 0 -> 336 bytes .../ri/UploadIO/cdesc-UploadIO.ri | Bin 0 -> 704 bytes .../ri/UploadIO/content_type-i.ri | Bin 0 -> 1027 bytes .../ri/UploadIO/convert%21-c.ri | Bin 0 -> 287 bytes .../multipart-post-2.0.0/ri/UploadIO/io-i.ri | Bin 0 -> 1007 bytes .../ri/UploadIO/local_path-i.ri | Bin 0 -> 1023 bytes .../ri/UploadIO/method_missing-i.ri | Bin 0 -> 256 bytes .../multipart-post-2.0.0/ri/UploadIO/new-c.ri | Bin 0 -> 285 bytes .../ri/UploadIO/opts-i.ri | Bin 0 -> 1011 bytes .../ri/UploadIO/original_filename-i.ri | Bin 0 -> 1037 bytes .../ri/UploadIO/respond_to%3f-i.ri | Bin 0 -> 270 bytes .gems/doc/multipart-post-2.0.0/ri/cache.ri | Bin 0 -> 1673 bytes .../Naught/BasicObject/cdesc-BasicObject.ri | Bin 0 -> 411 bytes .../ri/Naught/Conversions/Actual-i.ri | Bin 0 -> 274 bytes .../ri/Naught/Conversions/Just-i.ri | Bin 0 -> 270 bytes .../ri/Naught/Conversions/Maybe-i.ri | Bin 0 -> 272 bytes .../ri/Naught/Conversions/Null-i.ri | Bin 0 -> 276 bytes .../Naught/Conversions/cdesc-Conversions.ri | Bin 0 -> 506 bytes .../ri/Naught/Conversions/included-c.ri | Bin 0 -> 271 bytes .../NullClassBuilder/Command/builder-i.ri | Bin 0 -> 297 bytes .../Naught/NullClassBuilder/Command/call-i.ri | Bin 0 -> 276 bytes .../NullClassBuilder/Command/cdesc-Command.ri | Bin 0 -> 566 bytes .../NullClassBuilder/Command/defer-i.ri | Bin 0 -> 298 bytes .../Naught/NullClassBuilder/Command/new-c.ri | Bin 0 -> 282 bytes .../DefineExplicitConversions/call-i.ri | Bin 0 -> 351 bytes .../cdesc-DefineExplicitConversions.ri | Bin 0 -> 686 bytes .../DefineImplicitConversions/call-i.ri | Bin 0 -> 351 bytes .../cdesc-DefineImplicitConversions.ri | Bin 0 -> 683 bytes .../DefineImplicitConversions/to_ary-i.ri | Bin 0 -> 355 bytes .../DefineImplicitConversions/to_str-i.ri | Bin 0 -> 355 bytes .../Commands/Impersonate/cdesc-Impersonate.ri | Bin 0 -> 596 bytes .../Commands/Impersonate/new-c.ri | Bin 0 -> 349 bytes .../NullClassBuilder/Commands/Mimic/call-i.ri | Bin 0 -> 289 bytes .../Commands/Mimic/cdesc-Mimic.ri | Bin 0 -> 694 bytes .../Commands/Mimic/class_to_mimic-i.ri | Bin 0 -> 334 bytes .../Commands/Mimic/include_super-i.ri | Bin 0 -> 332 bytes .../Commands/Mimic/methods_to_stub-i.ri | Bin 0 -> 312 bytes .../NullClassBuilder/Commands/Mimic/new-c.ri | Bin 0 -> 325 bytes .../Commands/Mimic/root_class_of-i.ri | Bin 0 -> 313 bytes .../Commands/Pebble/call-i.ri | Bin 0 -> 292 bytes .../Commands/Pebble/cdesc-Pebble.ri | Bin 0 -> 606 bytes .../NullClassBuilder/Commands/Pebble/new-c.ri | Bin 0 -> 316 bytes .../Commands/Pebble/parse_caller-i.ri | Bin 0 -> 308 bytes .../Commands/PredicatesReturn/call-i.ri | Bin 0 -> 323 bytes .../cdesc-PredicatesReturn.ri | Bin 0 -> 692 bytes .../define_method_missing-i.ri | Bin 0 -> 365 bytes .../define_predicate_methods-i.ri | Bin 0 -> 371 bytes .../Commands/PredicatesReturn/new-c.ri | Bin 0 -> 343 bytes .../Commands/Singleton/call-i.ri | Bin 0 -> 301 bytes .../Commands/Singleton/cdesc-Singleton.ri | Bin 0 -> 632 bytes .../Commands/Singleton/get-c.ri | Bin 0 -> 301 bytes .../Commands/Traceable/call-i.ri | Bin 0 -> 301 bytes .../Commands/Traceable/cdesc-Traceable.ri | Bin 0 -> 595 bytes .../Commands/Traceable/new-c.ri | Bin 0 -> 312 bytes .../Commands/cdesc-Commands.ri | Bin 0 -> 1119 bytes .../NullClassBuilder/apply_operations-i.ri | Bin 0 -> 320 bytes .../Naught/NullClassBuilder/base_class-i.ri | Bin 0 -> 278 bytes .../Naught/NullClassBuilder/black_hole-i.ri | Bin 0 -> 434 bytes .../cdesc-NullClassBuilder.ri | Bin 0 -> 1842 bytes .../NullClassBuilder/class_operations-i.ri | Bin 0 -> 293 bytes .../command_name_for_method-i.ri | Bin 0 -> 318 bytes .../customization_module-i.ri | Bin 0 -> 300 bytes .../ri/Naught/NullClassBuilder/customize-i.ri | Bin 0 -> 298 bytes .../ri/Naught/NullClassBuilder/defer-i.ri | Bin 0 -> 303 bytes .../define_basic_class_methods-i.ri | Bin 0 -> 313 bytes .../define_basic_instance_methods-i.ri | Bin 0 -> 319 bytes .../define_basic_methods-i.ri | Bin 0 -> 301 bytes .../NullClassBuilder/generate_class-i.ri | Bin 0 -> 288 bytes .../ri/Naught/NullClassBuilder/get-c.ri | Bin 0 -> 268 bytes .../Naught/NullClassBuilder/inspect_proc-i.ri | Bin 0 -> 282 bytes .../interface_defined%3f-i.ri | Bin 0 -> 296 bytes .../NullClassBuilder/interface_defined-i.ri | Bin 0 -> 292 bytes .../NullClassBuilder/method_missing-i.ri | Bin 0 -> 314 bytes .../ri/Naught/NullClassBuilder/new-c.ri | Bin 0 -> 294 bytes .../NullClassBuilder/null_equivalents-i.ri | Bin 0 -> 292 bytes .../Naught/NullClassBuilder/operations-i.ri | Bin 0 -> 281 bytes .../NullClassBuilder/respond_to%3f-i.ri | Bin 0 -> 318 bytes .../respond_to_any_message-i.ri | Bin 0 -> 304 bytes .../respond_to_missing%3f-i.ri | Bin 0 -> 334 bytes .../Naught/NullClassBuilder/stub_method-i.ri | Bin 0 -> 295 bytes .../stub_method_returning_nil-i.ri | Bin 0 -> 324 bytes .../stub_method_returning_self-i.ri | Bin 0 -> 326 bytes .../NullObjectTag/cdesc-NullObjectTag.ri | Bin 0 -> 386 bytes .gems/doc/naught-1.0.0/ri/Naught/build-c.ri | Bin 0 -> 245 bytes .../naught-1.0.0/ri/Naught/cdesc-Naught.ri | Bin 0 -> 1243 bytes .gems/doc/naught-1.0.0/ri/cache.ri | Bin 0 -> 2902 bytes .../ri/SimpleOAuth/Header/attributes-i.ri | Bin 0 -> 260 bytes .../ri/SimpleOAuth/Header/cdesc-Header.ri | Bin 0 -> 1158 bytes .../ri/SimpleOAuth/Header/decode-c.ri | Bin 0 -> 257 bytes .../SimpleOAuth/Header/default_options-c.ri | Bin 0 -> 270 bytes .../ri/SimpleOAuth/Header/encode-c.ri | Bin 0 -> 257 bytes .../ri/SimpleOAuth/Header/escape-c.ri | Bin 0 -> 287 bytes .../Header/hmac_sha1_signature-i.ri | Bin 0 -> 278 bytes .../ri/SimpleOAuth/Header/method-i.ri | Bin 0 -> 253 bytes .../ri/SimpleOAuth/Header/new-c.ri | Bin 0 -> 277 bytes .../Header/normalized_attributes-i.ri | Bin 0 -> 282 bytes .../SimpleOAuth/Header/normalized_params-i.ri | Bin 0 -> 274 bytes .../ri/SimpleOAuth/Header/options-i.ri | Bin 0 -> 255 bytes .../ri/SimpleOAuth/Header/params-i.ri | Bin 0 -> 253 bytes .../ri/SimpleOAuth/Header/parse-c.ri | Bin 0 -> 256 bytes .../Header/plaintext_signature-i.ri | Bin 0 -> 278 bytes .../ri/SimpleOAuth/Header/private_key-i.ri | Bin 0 -> 262 bytes .../Header/rsa_sha1_signature-i.ri | Bin 0 -> 276 bytes .../ri/SimpleOAuth/Header/secret-i.ri | Bin 0 -> 295 bytes .../ri/SimpleOAuth/Header/signature-i.ri | Bin 0 -> 258 bytes .../ri/SimpleOAuth/Header/signature_base-i.ri | Bin 0 -> 268 bytes .../SimpleOAuth/Header/signature_params-i.ri | Bin 0 -> 272 bytes .../SimpleOAuth/Header/signed_attributes-i.ri | Bin 0 -> 273 bytes .../ri/SimpleOAuth/Header/to_s-i.ri | Bin 0 -> 247 bytes .../ri/SimpleOAuth/Header/unescape-c.ri | Bin 0 -> 291 bytes .../ri/SimpleOAuth/Header/uri_parser-c.ri | Bin 0 -> 261 bytes .../ri/SimpleOAuth/Header/url-i.ri | Bin 0 -> 245 bytes .../ri/SimpleOAuth/Header/url_params-i.ri | Bin 0 -> 260 bytes .../ri/SimpleOAuth/Header/valid%3f-i.ri | Bin 0 -> 263 bytes .../ri/SimpleOAuth/cdesc-SimpleOAuth.ri | Bin 0 -> 356 bytes .gems/doc/simple_oauth-0.2.0/ri/cache.ri | Bin 0 -> 938 bytes .../cdesc-SynchronizedDelegator.ri | Bin 0 -> 1372 bytes .../SynchronizedDelegator/method_missing-i.ri | Bin 0 -> 320 bytes .../ri/SynchronizedDelegator/new-c.ri | Bin 0 -> 281 bytes .../ri/SynchronizedDelegator/setup-i.ri | Bin 0 -> 281 bytes .../ri/SynchronizedDelegator/teardown-i.ri | Bin 0 -> 287 bytes .../ri/ThreadSafe/Array/cdesc-Array.ri | Bin 0 -> 461 bytes .../%5b%5d%3d-i.ri | Bin 0 -> 319 bytes .../AtomicReferenceCacheBackend/%5b%5d-i.ri | Bin 0 -> 310 bytes .../Node/Util/cdesc-Util.ri | Bin 0 -> 466 bytes .../Node/cdesc-Node.ri | Bin 0 -> 1938 bytes .../Node/force_aquire_lock-i.ri | Bin 0 -> 329 bytes .../Node/key%3f-i.ri | Bin 0 -> 297 bytes .../AtomicReferenceCacheBackend/Node/key-i.ri | Bin 0 -> 322 bytes .../Node/locked%3f-i.ri | Bin 0 -> 300 bytes .../Node/locked_hash%3f-c.ri | Bin 0 -> 316 bytes .../Node/matches%3f-i.ri | Bin 0 -> 311 bytes .../AtomicReferenceCacheBackend/Node/new-c.ri | Bin 0 -> 326 bytes .../Node/pure_hash-i.ri | Bin 0 -> 304 bytes .../Node/try_await_lock-i.ri | Bin 0 -> 1003 bytes .../Node/try_lock_via_hash-i.ri | Bin 0 -> 342 bytes .../Node/unlock_via_hash-i.ri | Bin 0 -> 338 bytes .../Table/cas_new_node-i.ri | Bin 0 -> 331 bytes .../Table/cdesc-Table.ri | Bin 0 -> 660 bytes .../Table/delete_node_at-i.ri | Bin 0 -> 341 bytes .../Table/try_lock_via_hash-i.ri | Bin 0 -> 346 bytes .../Table/try_to_cas_in_computed-i.ri | Bin 0 -> 354 bytes .../attempt_compute-i.ri | Bin 0 -> 389 bytes .../attempt_get_and_set-i.ri | Bin 0 -> 393 bytes .../attempt_internal_compute_if_absent-i.ri | Bin 0 -> 422 bytes .../attempt_internal_replace-i.ri | Bin 0 -> 431 bytes .../cdesc-AtomicReferenceCacheBackend.ri | Bin 0 -> 13767 bytes .../check_for_resize-i.ri | Bin 0 -> 602 bytes .../AtomicReferenceCacheBackend/clear-i.ri | Bin 0 -> 420 bytes .../AtomicReferenceCacheBackend/compute-i.ri | Bin 0 -> 361 bytes .../compute_if_absent-i.ri | Bin 0 -> 346 bytes .../compute_if_present-i.ri | Bin 0 -> 383 bytes .../AtomicReferenceCacheBackend/delete-i.ri | Bin 0 -> 318 bytes .../delete_pair-i.ri | Bin 0 -> 335 bytes .../each_pair-i.ri | Bin 0 -> 337 bytes .../AtomicReferenceCacheBackend/empty%3f-i.ri | Bin 0 -> 315 bytes .../find_value_in_node_list-i.ri | Bin 0 -> 376 bytes .../get_and_set-i.ri | Bin 0 -> 335 bytes .../get_or_default-i.ri | Bin 0 -> 352 bytes .../initialize_copy-i.ri | Bin 0 -> 339 bytes .../initialize_table-i.ri | Bin 0 -> 435 bytes .../internal_compute-i.ri | Bin 0 -> 347 bytes .../internal_replace-i.ri | Bin 0 -> 1213 bytes .../AtomicReferenceCacheBackend/key%3f-i.ri | Bin 0 -> 314 bytes .../AtomicReferenceCacheBackend/key_hash-i.ri | Bin 0 -> 323 bytes .../merge_pair-i.ri | Bin 0 -> 348 bytes .../AtomicReferenceCacheBackend/new-c.ri | Bin 0 -> 323 bytes .../replace_if_exists-i.ri | Bin 0 -> 351 bytes .../replace_pair-i.ri | Bin 0 -> 352 bytes .../AtomicReferenceCacheBackend/size-i.ri | Bin 0 -> 311 bytes .../table_size_for-i.ri | Bin 0 -> 446 bytes .../try_await_lock-i.ri | Bin 0 -> 354 bytes .../ri/ThreadSafe/Cache/%5b%5d-i.ri | Bin 0 -> 268 bytes .../ri/ThreadSafe/Cache/cdesc-Cache.ri | Bin 0 -> 973 bytes .../ri/ThreadSafe/Cache/each_key-i.ri | Bin 0 -> 257 bytes .../ri/ThreadSafe/Cache/each_value-i.ri | Bin 0 -> 261 bytes .../ri/ThreadSafe/Cache/empty%3f-i.ri | Bin 0 -> 246 bytes .../ri/ThreadSafe/Cache/fetch-i.ri | Bin 0 -> 278 bytes .../ri/ThreadSafe/Cache/fetch_or_store-i.ri | Bin 0 -> 296 bytes .../ri/ThreadSafe/Cache/get-i.ri | Bin 0 -> 243 bytes .../ri/ThreadSafe/Cache/index-i.ri | Bin 0 -> 249 bytes .../ri/ThreadSafe/Cache/initialize_copy-i.ri | Bin 0 -> 270 bytes .../ri/ThreadSafe/Cache/key-i.ri | Bin 0 -> 274 bytes .../ri/ThreadSafe/Cache/keys-i.ri | Bin 0 -> 242 bytes .../ri/ThreadSafe/Cache/marshal_dump-i.ri | Bin 0 -> 258 bytes .../ri/ThreadSafe/Cache/marshal_load-i.ri | Bin 0 -> 262 bytes .../ri/ThreadSafe/Cache/new-c.ri | Bin 0 -> 262 bytes .../ri/ThreadSafe/Cache/populate_from-i.ri | Bin 0 -> 265 bytes .../ri/ThreadSafe/Cache/put_if_absent-i.ri | Bin 0 -> 270 bytes .../ThreadSafe/Cache/raise_fetch_no_key-i.ri | Bin 0 -> 271 bytes .../ri/ThreadSafe/Cache/size-i.ri | Bin 0 -> 242 bytes .../Cache/validate_options_hash%21-i.ri | Bin 0 -> 286 bytes .../ri/ThreadSafe/Cache/value%3f-i.ri | Bin 0 -> 251 bytes .../ri/ThreadSafe/Cache/values-i.ri | Bin 0 -> 246 bytes .../ri/ThreadSafe/Hash/cdesc-Hash.ri | Bin 0 -> 458 bytes .../ThreadSafe/MriCacheBackend/%5b%5d%3d-i.ri | Bin 0 -> 282 bytes .../MriCacheBackend/cdesc-MriCacheBackend.ri | Bin 0 -> 1878 bytes .../ri/ThreadSafe/MriCacheBackend/clear-i.ri | Bin 0 -> 276 bytes .../ThreadSafe/MriCacheBackend/compute-i.ri | Bin 0 -> 283 bytes .../MriCacheBackend/compute_if_absent-i.ri | Bin 0 -> 303 bytes .../MriCacheBackend/compute_if_present-i.ri | Bin 0 -> 305 bytes .../ri/ThreadSafe/MriCacheBackend/delete-i.ri | Bin 0 -> 281 bytes .../MriCacheBackend/delete_pair-i.ri | Bin 0 -> 298 bytes .../MriCacheBackend/get_and_set-i.ri | Bin 0 -> 298 bytes .../MriCacheBackend/merge_pair-i.ri | Bin 0 -> 296 bytes .../MriCacheBackend/replace_if_exists-i.ri | Bin 0 -> 314 bytes .../MriCacheBackend/replace_pair-i.ri | Bin 0 -> 315 bytes .../NonConcurrentCacheBackend/%5b%5d%3d-i.ri | Bin 0 -> 341 bytes .../NonConcurrentCacheBackend/%5b%5d-i.ri | Bin 0 -> 332 bytes .../NonConcurrentCacheBackend/_get-i.ri | Bin 0 -> 309 bytes .../NonConcurrentCacheBackend/_set-i.ri | Bin 0 -> 316 bytes .../cdesc-NonConcurrentCacheBackend.ri | Bin 0 -> 1000 bytes .../NonConcurrentCacheBackend/clear-i.ri | Bin 0 -> 307 bytes .../NonConcurrentCacheBackend/compute-i.ri | Bin 0 -> 327 bytes .../compute_if_absent-i.ri | Bin 0 -> 340 bytes .../compute_if_present-i.ri | Bin 0 -> 354 bytes .../NonConcurrentCacheBackend/delete-i.ri | Bin 0 -> 312 bytes .../delete_pair-i.ri | Bin 0 -> 329 bytes .../dupped_backend-i.ri | Bin 0 -> 326 bytes .../NonConcurrentCacheBackend/each_pair-i.ri | Bin 0 -> 325 bytes .../get_and_set-i.ri | Bin 0 -> 329 bytes .../get_or_default-i.ri | Bin 0 -> 343 bytes .../initialize_copy-i.ri | Bin 0 -> 333 bytes .../NonConcurrentCacheBackend/key%3f-i.ri | Bin 0 -> 308 bytes .../NonConcurrentCacheBackend/merge_pair-i.ri | Bin 0 -> 345 bytes .../NonConcurrentCacheBackend/new-c.ri | Bin 0 -> 584 bytes .../NonConcurrentCacheBackend/pair%3f-i.ri | Bin 0 -> 327 bytes .../replace_if_exists-i.ri | Bin 0 -> 345 bytes .../replace_pair-i.ri | Bin 0 -> 346 bytes .../NonConcurrentCacheBackend/size-i.ri | Bin 0 -> 305 bytes .../store_computed_value-i.ri | Bin 0 -> 352 bytes .../NonConcurrentCacheBackend/value%3f-i.ri | Bin 0 -> 314 bytes .../SynchronizedCacheBackend/%5b%5d%3d-i.ri | Bin 0 -> 309 bytes .../SynchronizedCacheBackend/%5b%5d-i.ri | Bin 0 -> 443 bytes .../cdesc-SynchronizedCacheBackend.ri | Bin 0 -> 921 bytes .../SynchronizedCacheBackend/clear-i.ri | Bin 0 -> 303 bytes .../SynchronizedCacheBackend/compute-i.ri | Bin 0 -> 310 bytes .../compute_if_absent-i.ri | Bin 0 -> 330 bytes .../compute_if_present-i.ri | Bin 0 -> 332 bytes .../SynchronizedCacheBackend/delete-i.ri | Bin 0 -> 308 bytes .../SynchronizedCacheBackend/delete_pair-i.ri | Bin 0 -> 325 bytes .../dupped_backend-i.ri | Bin 0 -> 322 bytes .../SynchronizedCacheBackend/get_and_set-i.ri | Bin 0 -> 325 bytes .../get_or_default-i.ri | Bin 0 -> 339 bytes .../SynchronizedCacheBackend/key%3f-i.ri | Bin 0 -> 304 bytes .../SynchronizedCacheBackend/merge_pair-i.ri | Bin 0 -> 323 bytes .../replace_if_exists-i.ri | Bin 0 -> 341 bytes .../replace_pair-i.ri | Bin 0 -> 342 bytes .../SynchronizedCacheBackend/size-i.ri | Bin 0 -> 301 bytes .../SynchronizedCacheBackend/value%3f-i.ri | Bin 0 -> 310 bytes .../ri/ThreadSafe/Util/Adder/add-i.ri | Bin 0 -> 311 bytes .../ri/ThreadSafe/Util/Adder/cdesc-Adder.ri | Bin 0 -> 1626 bytes .../ri/ThreadSafe/Util/Adder/decrement-i.ri | Bin 0 -> 263 bytes .../ri/ThreadSafe/Util/Adder/increment-i.ri | Bin 0 -> 263 bytes .../ri/ThreadSafe/Util/Adder/reset-i.ri | Bin 0 -> 255 bytes .../ri/ThreadSafe/Util/Adder/sum-i.ri | Bin 0 -> 561 bytes .../Util/CheapLockable/cdesc-CheapLockable.ri | Bin 0 -> 1185 bytes .../Util/CheapLockable/cheap_broadcast-i.ri | Bin 0 -> 302 bytes .../Util/CheapLockable/cheap_synchronize-i.ri | Bin 0 -> 462 bytes .../Util/CheapLockable/cheap_wait-i.ri | Bin 0 -> 292 bytes .../PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri | Bin 0 -> 633 bytes .../Util/PowerOfTwoTuple/hash_to_index-i.ri | Bin 0 -> 308 bytes .../ThreadSafe/Util/PowerOfTwoTuple/new-c.ri | Bin 0 -> 289 bytes .../PowerOfTwoTuple/next_in_size_table-i.ri | Bin 0 -> 314 bytes .../PowerOfTwoTuple/volatile_get_by_hash-i.ri | Bin 0 -> 322 bytes .../PowerOfTwoTuple/volatile_set_by_hash-i.ri | Bin 0 -> 329 bytes .../Util/Striped64/Cell/cas_computed-i.ri | Bin 0 -> 301 bytes .../Util/Striped64/Cell/cdesc-Cell.ri | Bin 0 -> 862 bytes .../Util/Striped64/cas_base_computed-i.ri | Bin 0 -> 310 bytes .../Util/Striped64/cdesc-Striped64.ri | Bin 0 -> 5062 bytes .../Striped64/expand_table_unless_stale-i.ri | Bin 0 -> 321 bytes .../ri/ThreadSafe/Util/Striped64/free%3f-i.ri | Bin 0 -> 268 bytes .../Util/Striped64/hash_code%3d-i.ri | Bin 0 -> 282 bytes .../ThreadSafe/Util/Striped64/hash_code-i.ri | Bin 0 -> 438 bytes .../Util/Striped64/internal_reset-i.ri | Bin 0 -> 382 bytes .../ri/ThreadSafe/Util/Striped64/new-c.ri | Bin 0 -> 264 bytes .../Util/Striped64/retry_update-i.ri | Bin 0 -> 936 bytes .../Util/Striped64/try_in_busy-i.ri | Bin 0 -> 286 bytes .../Util/Striped64/try_initialize_cells-i.ri | Bin 0 -> 305 bytes .../Striped64/try_to_install_new_cell-i.ri | Bin 0 -> 318 bytes .../Util/Volatile/attr_volatile-i.ri | Bin 0 -> 944 bytes .../Util/Volatile/cdesc-Volatile.ri | Bin 0 -> 508 bytes .../ri/ThreadSafe/Util/VolatileTuple/cas-i.ri | Bin 0 -> 299 bytes .../Util/VolatileTuple/cdesc-VolatileTuple.ri | Bin 0 -> 1107 bytes .../Util/VolatileTuple/compare_and_set-i.ri | Bin 0 -> 350 bytes .../ThreadSafe/Util/VolatileTuple/each-i.ri | Bin 0 -> 287 bytes .../ri/ThreadSafe/Util/VolatileTuple/new-c.ri | Bin 0 -> 281 bytes .../ThreadSafe/Util/VolatileTuple/size-i.ri | Bin 0 -> 278 bytes .../Util/VolatileTuple/volatile_get-i.ri | Bin 0 -> 295 bytes .../Util/VolatileTuple/volatile_set-i.ri | Bin 0 -> 302 bytes .../XorShiftRandom/cdesc-XorShiftRandom.ri | Bin 0 -> 1168 bytes .../ThreadSafe/Util/XorShiftRandom/get-i.ri | Bin 0 -> 385 bytes .../Util/XorShiftRandom/xorshift-i.ri | Bin 0 -> 455 bytes .../ri/ThreadSafe/Util/cdesc-Util.ri | Bin 0 -> 1212 bytes .../ri/ThreadSafe/_mon_initialize-i.ri | Bin 0 -> 257 bytes .../ri/ThreadSafe/allocate-c.ri | Bin 0 -> 244 bytes .../ri/ThreadSafe/cdesc-ThreadSafe.ri | Bin 0 -> 2223 bytes .../ri/ThreadSafe/decrement_size-i.ri | Bin 0 -> 292 bytes .../ri/ThreadSafe/increment_size-i.ri | Bin 0 -> 286 bytes .../lock_and_clean_up_reverse_forwarders-i.ri | Bin 0 -> 380 bytes .../ri/ThreadSafe/rebuild-i.ri | Bin 0 -> 397 bytes .../ri/ThreadSafe/split_bin-i.ri | Bin 0 -> 305 bytes .../ri/ThreadSafe/split_old_bin-i.ri | Bin 0 -> 457 bytes .../ri/ThreadSafe/try_in_resize_lock-i.ri | Bin 0 -> 324 bytes .../ri/Threadsafe/cdesc-Threadsafe.ri | Bin 0 -> 503 bytes .../ri/Threadsafe/const_missing-c.ri | Bin 0 -> 312 bytes .gems/doc/thread_safe-0.3.4/ri/cache.ri | Bin 0 -> 5336 bytes .gems/gems/addressable-2.3.6/CHANGELOG.md | 170 + .gems/gems/addressable-2.3.6/Gemfile | 28 + .gems/gems/addressable-2.3.6/LICENSE.txt | 202 + .gems/gems/addressable-2.3.6/README.md | 102 + .gems/gems/addressable-2.3.6/Rakefile | 37 + .../gems/addressable-2.3.6/data/unicode.data | Bin 0 -> 115740 bytes .../addressable-2.3.6/lib/addressable/idna.rb | 25 + .../lib/addressable/idna/native.rb | 43 + .../lib/addressable/idna/pure.rb | 669 ++ .../lib/addressable/template.rb | 938 +++ .../addressable-2.3.6/lib/addressable/uri.rb | 2351 +++++++ .../lib/addressable/version.rb | 30 + .../spec/addressable/idna_spec.rb | 238 + .../spec/addressable/net_http_compat_spec.rb | 28 + .../spec/addressable/template_spec.rb | 1328 ++++ .../spec/addressable/uri_spec.rb | 5940 +++++++++++++++++ .../addressable-2.3.6/spec/spec_helper.rb | 6 + .../gems/addressable-2.3.6/tasks/clobber.rake | 2 + .gems/gems/addressable-2.3.6/tasks/gem.rake | 86 + .gems/gems/addressable-2.3.6/tasks/git.rake | 45 + .../gems/addressable-2.3.6/tasks/metrics.rake | 22 + .gems/gems/addressable-2.3.6/tasks/rspec.rake | 58 + .../addressable-2.3.6/tasks/rubyforge.rake | 73 + .gems/gems/addressable-2.3.6/tasks/yard.rake | 27 + .../gems/addressable-2.3.6/website/index.html | 110 + .gems/gems/buftok-0.2.0/CONTRIBUTING.md | 49 + .gems/gems/buftok-0.2.0/Gemfile | 6 + .gems/gems/buftok-0.2.0/LICENSE.md | 56 + .gems/gems/buftok-0.2.0/README.md | 48 + .gems/gems/buftok-0.2.0/Rakefile | 66 + .gems/gems/buftok-0.2.0/buftok.gemspec | 17 + .gems/gems/buftok-0.2.0/lib/buftok.rb | 59 + .gems/gems/buftok-0.2.0/test/test_buftok.rb | 27 + .gems/gems/equalizer-0.0.9/.gitignore | 37 + .gems/gems/equalizer-0.0.9/.reek.yml | 106 + .gems/gems/equalizer-0.0.9/.rspec | 5 + .gems/gems/equalizer-0.0.9/.rubocop.yml | 69 + .gems/gems/equalizer-0.0.9/.ruby-gemset | 1 + .gems/gems/equalizer-0.0.9/.travis.yml | 29 + .gems/gems/equalizer-0.0.9/.yardstick.yml | 2 + .gems/gems/equalizer-0.0.9/CONTRIBUTING.md | 11 + .gems/gems/equalizer-0.0.9/Gemfile | 28 + .gems/gems/equalizer-0.0.9/LICENSE | 21 + .gems/gems/equalizer-0.0.9/README.md | 97 + .gems/gems/equalizer-0.0.9/Rakefile | 39 + .gems/gems/equalizer-0.0.9/equalizer.gemspec | 21 + .gems/gems/equalizer-0.0.9/lib/equalizer.rb | 122 + .../equalizer-0.0.9/lib/equalizer/version.rb | 8 + .../gems/equalizer-0.0.9/spec/spec_helper.rb | 34 + .../spec/support/config_alias.rb | 5 + .../spec/unit/equalizer/included_spec.rb | 40 + .../equalizer/methods/eql_predicate_spec.rb | 65 + .../methods/equality_operator_spec.rb | 108 + .../spec/unit/equalizer/universal_spec.rb | 159 + .gems/gems/faraday-0.9.0/.document | 6 + .gems/gems/faraday-0.9.0/CHANGELOG.md | 15 + .gems/gems/faraday-0.9.0/CONTRIBUTING.md | 36 + .gems/gems/faraday-0.9.0/Gemfile | 29 + .gems/gems/faraday-0.9.0/LICENSE.md | 20 + .gems/gems/faraday-0.9.0/README.md | 216 + .gems/gems/faraday-0.9.0/Rakefile | 71 + .gems/gems/faraday-0.9.0/faraday.gemspec | 34 + .gems/gems/faraday-0.9.0/lib/faraday.rb | 268 + .../gems/faraday-0.9.0/lib/faraday/adapter.rb | 46 + .../lib/faraday/adapter/em_http.rb | 237 + .../lib/faraday/adapter/em_http_ssl_patch.rb | 56 + .../lib/faraday/adapter/em_synchrony.rb | 92 + .../adapter/em_synchrony/parallel_manager.rb | 66 + .../lib/faraday/adapter/excon.rb | 80 + .../lib/faraday/adapter/httpclient.rb | 106 + .../lib/faraday/adapter/net_http.rb | 124 + .../faraday/adapter/net_http_persistent.rb | 47 + .../lib/faraday/adapter/patron.rb | 68 + .../faraday-0.9.0/lib/faraday/adapter/rack.rb | 58 + .../faraday-0.9.0/lib/faraday/adapter/test.rb | 162 + .../lib/faraday/adapter/typhoeus.rb | 123 + .../faraday-0.9.0/lib/faraday/autoload.rb | 85 + .../faraday-0.9.0/lib/faraday/connection.rb | 432 ++ .gems/gems/faraday-0.9.0/lib/faraday/error.rb | 53 + .../faraday-0.9.0/lib/faraday/middleware.rb | 37 + .../gems/faraday-0.9.0/lib/faraday/options.rb | 350 + .../faraday-0.9.0/lib/faraday/parameters.rb | 193 + .../faraday-0.9.0/lib/faraday/rack_builder.rb | 212 + .../gems/faraday-0.9.0/lib/faraday/request.rb | 92 + .../lib/faraday/request/authorization.rb | 42 + .../faraday/request/basic_authentication.rb | 13 + .../lib/faraday/request/instrumentation.rb | 36 + .../lib/faraday/request/multipart.rb | 63 + .../lib/faraday/request/retry.rb | 118 + .../faraday/request/token_authentication.rb | 15 + .../lib/faraday/request/url_encoded.rb | 36 + .../faraday-0.9.0/lib/faraday/response.rb | 93 + .../lib/faraday/response/logger.rb | 34 + .../lib/faraday/response/raise_error.rb | 21 + .../faraday-0.9.0/lib/faraday/upload_io.rb | 67 + .gems/gems/faraday-0.9.0/lib/faraday/utils.rb | 297 + .gems/gems/faraday-0.9.0/script/console | 7 + .../gems/faraday-0.9.0/script/generate_certs | 42 + .gems/gems/faraday-0.9.0/script/package | 7 + .gems/gems/faraday-0.9.0/script/proxy-server | 42 + .gems/gems/faraday-0.9.0/script/release | 17 + .gems/gems/faraday-0.9.0/script/server | 36 + .gems/gems/faraday-0.9.0/script/test | 172 + .../test/adapters/default_test.rb | 14 + .../test/adapters/em_http_test.rb | 20 + .../test/adapters/em_synchrony_test.rb | 20 + .../faraday-0.9.0/test/adapters/excon_test.rb | 20 + .../test/adapters/httpclient_test.rb | 21 + .../test/adapters/integration.rb | 254 + .../test/adapters/logger_test.rb | 37 + .../test/adapters/net_http_persistent_test.rb | 20 + .../test/adapters/net_http_test.rb | 14 + .../test/adapters/patron_test.rb | 20 + .../faraday-0.9.0/test/adapters/rack_test.rb | 31 + .../test/adapters/test_middleware_test.rb | 114 + .../test/adapters/typhoeus_test.rb | 28 + .../test/authentication_middleware_test.rb | 65 + .../test/composite_read_io_test.rb | 111 + .../faraday-0.9.0/test/connection_test.rb | 522 ++ .gems/gems/faraday-0.9.0/test/env_test.rb | 210 + .gems/gems/faraday-0.9.0/test/helper.rb | 81 + .gems/gems/faraday-0.9.0/test/live_server.rb | 67 + .../test/middleware/instrumentation_test.rb | 88 + .../test/middleware/retry_test.rb | 109 + .../test/middleware_stack_test.rb | 173 + .gems/gems/faraday-0.9.0/test/multibyte.txt | 1 + .gems/gems/faraday-0.9.0/test/options_test.rb | 252 + .../test/request_middleware_test.rb | 142 + .../test/response_middleware_test.rb | 72 + .gems/gems/faraday-0.9.0/test/strawberry.rb | 2 + .gems/gems/faraday-0.9.0/test/utils_test.rb | 58 + .gems/gems/http-0.6.2/.coveralls.yml | 1 + .gems/gems/http-0.6.2/.gitignore | 18 + .gems/gems/http-0.6.2/.rspec | 5 + .gems/gems/http-0.6.2/.rubocop.yml | 116 + .gems/gems/http-0.6.2/.travis.yml | 21 + .gems/gems/http-0.6.2/CHANGES.md | 132 + .gems/gems/http-0.6.2/Gemfile | 31 + .gems/gems/http-0.6.2/Guardfile | 9 + .gems/gems/http-0.6.2/LICENSE.txt | 20 + .gems/gems/http-0.6.2/README.md | 259 + .gems/gems/http-0.6.2/Rakefile | 29 + .../parallel_requests_with_celluloid.rb | 38 + .gems/gems/http-0.6.2/http.gemspec | 29 + .gems/gems/http-0.6.2/lib/http.rb | 24 + .../lib/http/authorization_header.rb | 37 + .../http/authorization_header/basic_auth.rb | 24 + .../http/authorization_header/bearer_token.rb | 28 + .gems/gems/http-0.6.2/lib/http/backports.rb | 2 + .../http-0.6.2/lib/http/backports/base64.rb | 6 + .../gems/http-0.6.2/lib/http/backports/uri.rb | 131 + .gems/gems/http-0.6.2/lib/http/chainable.rb | 143 + .gems/gems/http-0.6.2/lib/http/client.rb | 137 + .../gems/http-0.6.2/lib/http/content_type.rb | 27 + .gems/gems/http-0.6.2/lib/http/errors.rb | 13 + .gems/gems/http-0.6.2/lib/http/headers.rb | 154 + .../gems/http-0.6.2/lib/http/headers/mixin.rb | 11 + .gems/gems/http-0.6.2/lib/http/mime_type.rb | 76 + .../http-0.6.2/lib/http/mime_type/adapter.rb | 24 + .../http-0.6.2/lib/http/mime_type/json.rb | 23 + .gems/gems/http-0.6.2/lib/http/options.rb | 130 + .gems/gems/http-0.6.2/lib/http/redirector.rb | 66 + .gems/gems/http-0.6.2/lib/http/request.rb | 153 + .../http-0.6.2/lib/http/request/writer.rb | 84 + .gems/gems/http-0.6.2/lib/http/response.rb | 137 + .../gems/http-0.6.2/lib/http/response/body.rb | 64 + .../http-0.6.2/lib/http/response/parser.rb | 66 + .gems/gems/http-0.6.2/lib/http/version.rb | 3 + .gems/gems/http-0.6.2/logo.png | Bin 0 -> 29762 bytes .../authorization_header/basic_auth_spec.rb | 29 + .../authorization_header/bearer_token_spec.rb | 36 + .../spec/http/authorization_header_spec.rb | 41 + .../spec/http/backports/base64_spec.rb | 13 + .../spec/http/backports/uri_spec.rb | 9 + .../gems/http-0.6.2/spec/http/client_spec.rb | 202 + .../http-0.6.2/spec/http/content_type_spec.rb | 47 + .../spec/http/headers/mixin_spec.rb | 36 + .../gems/http-0.6.2/spec/http/headers_spec.rb | 417 ++ .../http-0.6.2/spec/http/options/body_spec.rb | 17 + .../http-0.6.2/spec/http/options/form_spec.rb | 17 + .../spec/http/options/headers_spec.rb | 22 + .../http-0.6.2/spec/http/options/json_spec.rb | 17 + .../spec/http/options/merge_spec.rb | 51 + .../http-0.6.2/spec/http/options/new_spec.rb | 30 + .../spec/http/options/proxy_spec.rb | 21 + .../gems/http-0.6.2/spec/http/options_spec.rb | 14 + .../http-0.6.2/spec/http/redirector_spec.rb | 100 + .../spec/http/request/writer_spec.rb | 43 + .../gems/http-0.6.2/spec/http/request_spec.rb | 147 + .../spec/http/response/body_spec.rb | 42 + .../http-0.6.2/spec/http/response_spec.rb | 100 + .gems/gems/http-0.6.2/spec/http_spec.rb | 136 + .gems/gems/http-0.6.2/spec/spec_helper.rb | 33 + .../http-0.6.2/spec/support/example_server.rb | 102 + .../http-0.6.2/spec/support/proxy_server.rb | 31 + .gems/gems/http_parser.rb-0.6.0/.gitignore | 11 + .gems/gems/http_parser.rb-0.6.0/.gitmodules | 6 + .gems/gems/http_parser.rb-0.6.0/Gemfile | 2 + .gems/gems/http_parser.rb-0.6.0/Gemfile.lock | 39 + .gems/gems/http_parser.rb-0.6.0/LICENSE-MIT | 20 + .gems/gems/http_parser.rb-0.6.0/README.md | 90 + .gems/gems/http_parser.rb-0.6.0/Rakefile | 6 + .../http_parser.rb-0.6.0/bench/standalone.rb | 23 + .gems/gems/http_parser.rb-0.6.0/bench/thin.rb | 58 + .../ext/ruby_http_parser/.RUBYARCHDIR.time | 0 .../ext/ruby_http_parser/.gitignore | 1 + .../RubyHttpParserService.java | 18 + .../ext/ruby_http_parser/ext_help.h | 18 + .../ext/ruby_http_parser/extconf.rb | 24 + .../org/ruby_http_parser/RubyHttpParser.java | 495 ++ .../ext/ruby_http_parser/ruby_http_parser.c | 515 ++ .../ext/ruby_http_parser/vendor/.gitkeep | 0 .../vendor/http-parser-java/AUTHORS | 32 + .../vendor/http-parser-java/LICENSE-MIT | 48 + .../vendor/http-parser-java/README.md | 183 + .../vendor/http-parser-java/TODO | 28 + .../vendor/http-parser-java/build.xml | 74 + .../vendor/http-parser-java/http_parser.c | 2175 ++++++ .../vendor/http-parser-java/http_parser.gyp | 79 + .../vendor/http-parser-java/http_parser.h | 304 + .../http-parser-java/src/Http-parser.java.iml | 22 + .../src/impl/http_parser/FieldData.java | 41 + .../src/impl/http_parser/HTTPCallback.java | 8 + .../impl/http_parser/HTTPDataCallback.java | 34 + .../impl/http_parser/HTTPErrorCallback.java | 12 + .../src/impl/http_parser/HTTPException.java | 9 + .../src/impl/http_parser/HTTPMethod.java | 107 + .../src/impl/http_parser/HTTPParser.java | 36 + .../src/impl/http_parser/HTTPParserUrl.java | 76 + .../src/impl/http_parser/ParserSettings.java | 256 + .../src/impl/http_parser/ParserType.java | 13 + .../src/impl/http_parser/Util.java | 111 + .../http_parser/lolevel/HTTPCallback.java | 5 + .../http_parser/lolevel/HTTPDataCallback.java | 25 + .../lolevel/HTTPErrorCallback.java | 7 + .../impl/http_parser/lolevel/HTTPParser.java | 2161 ++++++ .../http_parser/lolevel/ParserSettings.java | 83 + .../src/test/http_parser/lolevel/Message.java | 374 ++ .../test/http_parser/lolevel/ParseUrl.java | 51 + .../test/http_parser/lolevel/Requests.java | 69 + .../test/http_parser/lolevel/Responses.java | 52 + .../src/test/http_parser/lolevel/Test.java | 16 + .../lolevel/TestHeaderOverflowError.java | 48 + .../http_parser/lolevel/TestLoaderNG.java | 212 + .../lolevel/TestNoOverflowLongBody.java | 62 + .../test/http_parser/lolevel/UnitTest.java | 117 + .../src/test/http_parser/lolevel/Upgrade.java | 27 + .../src/test/http_parser/lolevel/Url.java | 127 + .../src/test/http_parser/lolevel/Util.java | 236 + .../lolevel/WrongContentLength.java | 59 + .../vendor/http-parser-java/test.c | 3425 ++++++++++ .../vendor/http-parser-java/tests.dumped | 845 +++ .../vendor/http-parser-java/tests.utf8 | 17 + .../http-parser-java/tools/byte_constants.rb | 6 + .../http-parser-java/tools/const_char.rb | 13 + .../vendor/http-parser-java/tools/lowcase.rb | 15 + .../http-parser-java/tools/parse_tests.rb | 33 + .../vendor/http-parser/AUTHORS | 32 + .../vendor/http-parser/CONTRIBUTIONS | 4 + .../vendor/http-parser/LICENSE-MIT | 23 + .../vendor/http-parser/README.md | 178 + .../vendor/http-parser/http_parser.c | 2058 ++++++ .../vendor/http-parser/http_parser.gyp | 79 + .../vendor/http-parser/http_parser.h | 312 + .../vendor/http-parser/test.c | 2876 ++++++++ .../http_parser.rb.gemspec | 28 + .../http_parser.rb-0.6.0/lib/http/parser.rb | 1 + .../http_parser.rb-0.6.0/lib/http_parser.rb | 21 + .../http_parser.rb-0.6.0/spec/parser_spec.rb | 350 + .../http_parser.rb-0.6.0/spec/spec_helper.rb | 1 + .../spec/support/requests.json | 612 ++ .../spec/support/responses.json | 375 ++ .../http_parser.rb-0.6.0/tasks/compile.rake | 42 + .../http_parser.rb-0.6.0/tasks/fixtures.rake | 71 + .../gems/http_parser.rb-0.6.0/tasks/spec.rake | 5 + .../tasks/submodules.rake | 7 + .gems/gems/memoizable-0.4.2/CONTRIBUTING.md | 11 + .gems/gems/memoizable-0.4.2/LICENSE.md | 20 + .gems/gems/memoizable-0.4.2/README.md | 111 + .gems/gems/memoizable-0.4.2/Rakefile | 10 + .gems/gems/memoizable-0.4.2/lib/memoizable.rb | 33 + .../lib/memoizable/instance_methods.rb | 49 + .../memoizable-0.4.2/lib/memoizable/memory.rb | 104 + .../lib/memoizable/method_builder.rb | 145 + .../lib/memoizable/module_methods.rb | 125 + .../lib/memoizable/version.rb | 8 + .../gems/memoizable-0.4.2/memoizable.gemspec | 24 + .../spec/integration/serializable_spec.rb | 34 + .../spec/shared/call_super_shared_spec.rb | 23 + .../spec/shared/command_method_behavior.rb | 7 + .../gems/memoizable-0.4.2/spec/spec_helper.rb | 33 + .../memoizable/class_methods/included_spec.rb | 18 + .../spec/unit/memoizable/fixtures/classes.rb | 41 + .../instance_methods/freeze_spec.rb | 27 + .../instance_methods/memoize_spec.rb | 40 + .../spec/unit/memoizable/memory_spec.rb | 24 + .../memoizable/method_builder/call_spec.rb | 93 + .../method_builder/class_methods/new_spec.rb | 34 + .../method_builder/original_method_spec.rb | 31 + .../module_methods/included_spec.rb | 23 + .../memoizable/module_methods/memoize_spec.rb | 123 + .../module_methods/memoized_predicate_spec.rb | 28 + .../unmemoized_instance_method_spec.rb | 43 + .gems/gems/multipart-post-2.0.0/.gitignore | 6 + .gems/gems/multipart-post-2.0.0/.travis.yml | 7 + .gems/gems/multipart-post-2.0.0/Gemfile | 14 + .gems/gems/multipart-post-2.0.0/History.txt | 60 + .gems/gems/multipart-post-2.0.0/Manifest.txt | 9 + .gems/gems/multipart-post-2.0.0/README.md | 77 + .gems/gems/multipart-post-2.0.0/Rakefile | 9 + .../multipart-post-2.0.0/lib/composite_io.rb | 108 + .../lib/multipart_post.rb | 9 + .../multipart-post-2.0.0/lib/multipartable.rb | 29 + .../lib/net/http/post/multipart.rb | 27 + .gems/gems/multipart-post-2.0.0/lib/parts.rb | 96 + .../multipart-post.gemspec | 22 + .../multipart-post-2.0.0/test/multibyte.txt | 1 + .../test/net/http/post/test_multipart.rb | 110 + .../test/test_composite_io.rb | 115 + .../multipart-post-2.0.0/test/test_parts.rb | 86 + .gems/gems/naught-1.0.0/.gitignore | 23 + .gems/gems/naught-1.0.0/.rspec | 2 + .gems/gems/naught-1.0.0/.rubocop.yml | 74 + .gems/gems/naught-1.0.0/.travis.yml | 20 + .gems/gems/naught-1.0.0/Changelog.md | 12 + .gems/gems/naught-1.0.0/Gemfile | 31 + .gems/gems/naught-1.0.0/Guardfile | 15 + .gems/gems/naught-1.0.0/LICENSE.txt | 22 + .gems/gems/naught-1.0.0/README.markdown | 436 ++ .gems/gems/naught-1.0.0/Rakefile | 15 + .gems/gems/naught-1.0.0/lib/naught.rb | 13 + .../naught-1.0.0/lib/naught/basic_object.rb | 17 + .../naught-1.0.0/lib/naught/conversions.rb | 55 + .../lib/naught/null_class_builder.rb | 186 + .../lib/naught/null_class_builder/command.rb | 20 + .../lib/naught/null_class_builder/commands.rb | 8 + .../commands/define_explicit_conversions.rb | 15 + .../commands/define_implicit_conversions.rb | 19 + .../commands/impersonate.rb | 8 + .../null_class_builder/commands/mimic.rb | 37 + .../null_class_builder/commands/pebble.rb | 34 + .../commands/predicates_return.rb | 46 + .../null_class_builder/commands/singleton.rb | 24 + .../null_class_builder/commands/traceable.rb | 20 + .gems/gems/naught-1.0.0/lib/naught/version.rb | 3 + .gems/gems/naught-1.0.0/naught.gemspec | 22 + .../naught-1.0.0/spec/base_object_spec.rb | 47 + .../spec/basic_null_object_spec.rb | 35 + .../gems/naught-1.0.0/spec/blackhole_spec.rb | 16 + .../spec/explicit_conversions_spec.rb | 23 + .../spec/functions/actual_spec.rb | 22 + .../naught-1.0.0/spec/functions/just_spec.rb | 22 + .../naught-1.0.0/spec/functions/maybe_spec.rb | 35 + .../naught-1.0.0/spec/functions/null_spec.rb | 34 + .../spec/implicit_conversions_spec.rb | 25 + .gems/gems/naught-1.0.0/spec/mimic_spec.rb | 117 + .../null_object_builder/command_spec.rb | 10 + .../spec/naught/null_object_builder_spec.rb | 31 + .gems/gems/naught-1.0.0/spec/naught_spec.rb | 101 + .gems/gems/naught-1.0.0/spec/pebble_spec.rb | 77 + .../gems/naught-1.0.0/spec/predicate_spec.rb | 84 + .../spec/singleton_null_object_spec.rb | 35 + .gems/gems/naught-1.0.0/spec/spec_helper.rb | 13 + .../spec/support/convertable_null.rb | 4 + .gems/gems/naught-1.0.0/spec/support/jruby.rb | 3 + .../naught-1.0.0/spec/support/rubinius.rb | 3 + .../gems/naught-1.0.0/spec/support/ruby_18.rb | 3 + .gems/gems/simple_oauth-0.2.0/.gemtest | 0 .gems/gems/simple_oauth-0.2.0/.gitignore | 9 + .gems/gems/simple_oauth-0.2.0/.rspec | 3 + .gems/gems/simple_oauth-0.2.0/.travis.yml | 10 + .gems/gems/simple_oauth-0.2.0/.yardopts | 4 + .gems/gems/simple_oauth-0.2.0/CONTRIBUTING.md | 8 + .gems/gems/simple_oauth-0.2.0/Gemfile | 7 + .gems/gems/simple_oauth-0.2.0/LICENSE | 22 + .gems/gems/simple_oauth-0.2.0/README.md | 33 + .gems/gems/simple_oauth-0.2.0/Rakefile | 6 + .../simple_oauth-0.2.0/lib/simple_oauth.rb | 1 + .../lib/simple_oauth/header.rb | 126 + .../simple_oauth-0.2.0/simple_oauth.gemspec | 21 + .gems/gems/simple_oauth-0.2.0/spec/helper.rb | 21 + .../spec/simple_oauth/header_spec.rb | 372 ++ .../spec/support/fixtures/rsa-private-key | 16 + .../simple_oauth-0.2.0/spec/support/rsa.rb | 11 + .gems/gems/thread_safe-0.3.4/.travis.yml | 24 + .gems/gems/thread_safe-0.3.4/Gemfile | 4 + .gems/gems/thread_safe-0.3.4/LICENSE | 144 + .gems/gems/thread_safe-0.3.4/README.md | 56 + .gems/gems/thread_safe-0.3.4/Rakefile | 48 + .../thread_safe-0.3.4/examples/bench_cache.rb | 35 + .../thread_safe/JRubyCacheBackendLibrary.java | 245 + .../jsr166e/ConcurrentHashMap.java | 31 + .../jsr166e/ConcurrentHashMapV8.java | 3863 +++++++++++ .../ext/thread_safe/jsr166e/LongAdder.java | 203 + .../ext/thread_safe/jsr166e/Striped64.java | 342 + .../jsr166e/nounsafe/ConcurrentHashMapV8.java | 3800 +++++++++++ .../jsr166e/nounsafe/LongAdder.java | 204 + .../jsr166e/nounsafe/Striped64.java | 291 + .../jsr166y/ThreadLocalRandom.java | 199 + .../thread_safe/JrubyCacheBackendService.java | 15 + .../gems/thread_safe-0.3.4/lib/thread_safe.rb | 65 + .../atomic_reference_cache_backend.rb | 922 +++ .../lib/thread_safe/cache.rb | 163 + .../lib/thread_safe/mri_cache_backend.rb | 62 + .../non_concurrent_cache_backend.rb | 133 + .../thread_safe/synchronized_cache_backend.rb | 76 + .../lib/thread_safe/synchronized_delegator.rb | 60 + .../thread_safe-0.3.4/lib/thread_safe/util.rb | 16 + .../lib/thread_safe/util/adder.rb | 59 + .../lib/thread_safe/util/atomic_reference.rb | 45 + .../lib/thread_safe/util/cheap_lockable.rb | 105 + .../thread_safe/util/power_of_two_tuple.rb | 26 + .../lib/thread_safe/util/striped64.rb | 226 + .../lib/thread_safe/util/volatile.rb | 62 + .../lib/thread_safe/util/volatile_tuple.rb | 46 + .../lib/thread_safe/util/xor_shift_random.rb | 39 + .../lib/thread_safe/version.rb | 21 + .../test/src/thread_safe/SecurityManager.java | 21 + .../gems/thread_safe-0.3.4/test/test_array.rb | 18 + .../gems/thread_safe-0.3.4/test/test_cache.rb | 901 +++ .../test/test_cache_loops.rb | 449 ++ .../gems/thread_safe-0.3.4/test/test_hash.rb | 17 + .../thread_safe-0.3.4/test/test_helper.rb | 113 + .../test/test_synchronized_delegator.rb | 84 + .../thread_safe-0.3.4/thread_safe.gemspec | 26 + .../specifications/addressable-2.3.6.gemspec | 39 + .gems/specifications/buftok-0.2.0.gemspec | 29 + .gems/specifications/equalizer-0.0.9.gemspec | 31 + .gems/specifications/faraday-0.9.0.gemspec | 31 + .gems/specifications/http-0.6.2.gemspec | 32 + .../http_parser.rb-0.6.0.gemspec | 46 + .gems/specifications/memoizable-0.4.2.gemspec | 34 + .../multipart-post-2.0.0.gemspec | 19 + .gems/specifications/naught-1.0.0.gemspec | 29 + .../specifications/simple_oauth-0.2.0.gemspec | 35 + .../specifications/thread_safe-0.3.4.gemspec | 35 + .gems/specifications/twitter-5.11.0.gemspec | 2 +- 1580 files changed, 63513 insertions(+), 1 deletion(-) create mode 100644 .gems/cache/addressable-2.3.6.gem create mode 100644 .gems/cache/buftok-0.2.0.gem create mode 100644 .gems/cache/equalizer-0.0.9.gem create mode 100644 .gems/cache/faraday-0.9.0.gem create mode 100644 .gems/cache/http-0.6.2.gem create mode 100644 .gems/cache/http_parser.rb-0.6.0.gem create mode 100644 .gems/cache/memoizable-0.4.2.gem create mode 100644 .gems/cache/multipart-post-2.0.0.gem create mode 100644 .gems/cache/naught-1.0.0.gem create mode 100644 .gems/cache/simple_oauth-0.2.0.gem create mode 100644 .gems/cache/thread_safe-0.3.4.gem create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeBadInput/cdesc-PunycodeBadInput.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeBigOutput/cdesc-PunycodeBigOutput.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeOverflow/cdesc-PunycodeOverflow.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/cdesc-IDNA.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_combining_class-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_compatibility-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_composition-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_lowercase-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_adapt-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_basic%3f-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_decode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_decode_digit-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_delimiter%3f-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_encode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_encode_digit-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/to_ascii-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/to_unicode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_compose-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_compose_pair-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_decompose-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_decompose_hangul-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_downcase-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_normalize_kc-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_sort_canonical-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/%3d%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/InvalidTemplateOperatorError/cdesc-InvalidTemplateOperatorError.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/InvalidTemplateValueError/cdesc-InvalidTemplateValueError.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/%5b%5d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/captures-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/cdesc-MatchData.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/inspect-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/keys-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/mapping-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/names-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/new-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/post_match-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/pre_match-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/string-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/template-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/to_a-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/to_s-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/uri-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/values-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/values_at-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/variables-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/TemplateOperatorAbortedError/cdesc-TemplateOperatorAbortedError.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/cdesc-Template.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/eql%3f-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/expand-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/extract-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/inspect-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/join_values-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/keys-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/match-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/new-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/normalize_keys-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/normalize_value-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/ordered_variable_defaults-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/parse_template_pattern-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/partial_expand-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/pattern-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/transform_capture-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/transform_partial_capture-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/variable_defaults-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/Template/variables-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/%2b-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/%3d%3d%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/%3d%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/CharacterClasses/cdesc-CharacterClasses.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/InvalidURIError/cdesc-InvalidURIError.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/absolute%3f-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/authority%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/authority-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/basename-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/cdesc-URI.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/convert_path-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/default_port-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/defer_validation-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/display_uri-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/dup-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/empty%3f-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/encode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/encode_component-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/eql%3f-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/escape-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/extname-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/form_encode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/form_unencode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/fragment%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/fragment-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/freeze-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/hash-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/heuristic_parse-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/host%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/host-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/hostname%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/hostname-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/inferred_port-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/inspect-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/ip_based%3f-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/ip_based_schemes-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/join%21-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/join-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/join-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/merge%21-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/merge-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/new-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize%21-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize_component-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize_path-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_authority-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_encode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_fragment-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_host-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_password-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_path-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_port-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_query-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_scheme-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_site-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_user-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_userinfo-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/omit%21-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/omit-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/origin-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/parse-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/password%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/password-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/path%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/path-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/port%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/port-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/port_mapping-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/query%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/query-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/query_values%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/query_values-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/relative%3f-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/replace_self-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/request_uri%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/request_uri-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/route_from-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/route_to-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/scheme%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/scheme-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/site%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/site-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/split_path-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/to_hash-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/to_s-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/to_str-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/unencode-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/unencode_component-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/unescape-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/unescape_component-c.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/user%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/user-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/userinfo%3d-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/userinfo-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/URI/validate-i.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/VERSION/cdesc-VERSION.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/Addressable/cdesc-Addressable.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/cache.ri create mode 100644 .gems/doc/addressable-2.3.6/ri/page-README_md.ri create mode 100644 .gems/doc/buftok-0.2.0/ri/BufferedTokenizer/cdesc-BufferedTokenizer.ri create mode 100644 .gems/doc/buftok-0.2.0/ri/BufferedTokenizer/extract-i.ri create mode 100644 .gems/doc/buftok-0.2.0/ri/BufferedTokenizer/flush-i.ri create mode 100644 .gems/doc/buftok-0.2.0/ri/BufferedTokenizer/new-c.ri create mode 100644 .gems/doc/buftok-0.2.0/ri/cache.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/Methods/%3d%3d-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/Methods/cdesc-Methods.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/Methods/eql%3f-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/cdesc-Equalizer.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/define_cmp_method-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/define_hash_method-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/define_inspect_method-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/define_methods-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/included-i.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/Equalizer/new-c.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/cache.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/page-CONTRIBUTING_md.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/page-LICENSE.ri create mode 100644 .gems/doc/equalizer-0.0.9/ri/page-README_md.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/cdesc-EmHttpSslPatch.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/certificate_store-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/host-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/ssl_handshake_completed-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/ssl_verify_peer-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/verify_peer%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/EventMachine/cdesc-EventMachine.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/add-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/cdesc-Manager.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/check_finished-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/perform_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/reset-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/run-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/running%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/cdesc-Options.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_compression-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_proxy-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_socket-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_ssl-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_timeout-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/connection_config-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/read_body-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/request_config-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/request_options-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/cdesc-EMHttp.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/error_message-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/parallel%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/perform_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/perform_single_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/raise_error-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/setup_parallel_manager-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/add-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/cdesc-ParallelManager.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/perform-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/queue-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/run-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/cdesc-EMSynchrony.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/setup_parallel_manager-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/cdesc-Excon.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/read_body-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/cdesc-HTTPClient.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/client-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_proxy-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_socket-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_ssl-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_timeouts-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/ssl_verify_mode-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/OpenSSL/SSL/cdesc-SSL.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/OpenSSL/cdesc-OpenSSL.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/cdesc-NetHttp.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/configure_ssl-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/create_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/net_http_connection-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/perform_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/ssl_cert_store-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/ssl_verify_mode-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/cdesc-NetHttpPersistent.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/configure_ssl-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/net_http_connection-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/perform_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/proxy_uri;/cdesc-proxy_uri;.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/cdesc-Parallelism.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/inherited-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/supports_parallel%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/supports_parallel-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/Request/cdesc-Request.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/cdesc-Patron.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/create_session-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/cdesc-Rack.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/execute_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/cdesc-Stub.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/headers_match%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/matches%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/params_match%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/to_s-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/NotFound/cdesc-NotFound.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/cdesc-Stubs.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/delete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/empty%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/get-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/head-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/match-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/matches%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/new_stub-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/options-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/patch-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/post-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/put-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/verify_stubbed_calls-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/cdesc-Test.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/configure-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/stubs-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/cdesc-Typhoeus.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/configure_proxy-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/configure_socket-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/configure_ssl-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/configure_timeout-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/parallel%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/perform_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/read_body-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/request_options-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/setup_parallel_manager-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/cdesc-Adapter.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Adapter/save_response-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/all_loaded_constants-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/autoload_all-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/cdesc-AutoloadHelper.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/load_autoloaded_constants-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ClientError/backtrace-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ClientError/cdesc-ClientError.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ClientError/inspect-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ClientError/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ClientError/response-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/advance_io-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/cdesc-CompositeReadIO.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/close-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/current_io-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/ensure_open_and_readable-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/length-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/read-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/rewind-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/authorization-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/basic_auth-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/build_exclusive_url-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/build_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/build_url-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/builder-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/cdesc-Connection.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/default_parallel_manager-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/dup-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/headers%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/headers-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/in_parallel%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/in_parallel-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/options-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/parallel_manager-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/params%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/params-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/path_prefix%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/proxy-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/run_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/set_authorization_header-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/ssl-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/token_auth-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/url_prefix%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/url_prefix-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Connection/with_uri_credentials-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ConnectionFailed/cdesc-ConnectionFailed.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ConnectionOptions/cdesc-ConnectionOptions.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ConnectionOptions/new_builder-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/%5b%5d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/%5b%5d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/Utils/cdesc-Utils.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/cdesc-Env.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/clear_body-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/custom_members-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/in_member_set%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/inspect-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/member_set-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/needs_body%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/parallel%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/parse_body%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Env/success%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Error/cdesc-Error.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/cdesc-FlatParamsEncoder.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/decode-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/encode-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/escape-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/unescape-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Middleware/cdesc-Middleware.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Middleware/dependency-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Middleware/inherited-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Middleware/load_error-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Middleware/loaded%3f-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Middleware/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/cdesc-MiddlewareRegistry.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/fetch_middleware-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/load_middleware-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/lookup_middleware-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/middleware_mutex-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/register_middleware-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/MissingDependency/cdesc-MissingDependency.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/cdesc-NestedParamsEncoder.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/decode-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/encode-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/escape-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/unescape-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/%5b%5d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/attribute_options-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/cdesc-Options.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/clear-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/delete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/each-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/each_key-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/each_value-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/empty%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/fetch-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/fetch_error_class-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/from-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/has_key%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/has_value%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/inherited-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/inspect-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/key%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/keys-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/memoized-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/memoized_attributes-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/merge%21-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/merge-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/options-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/options_for-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/symbolized_key_set-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/to_hash-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/update-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/value%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Options/values_at-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ParsingError/cdesc-ParsingError.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ProxyOptions/cdesc-ProxyOptions.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ProxyOptions/from-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/%3d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/%5b%5d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/%3d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/build-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/cdesc-Handler.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/inspect-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/klass-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/name-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/StackLocked/cdesc-StackLocked.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/adapter-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/app-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/assert_index-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build_env-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build_response-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/cdesc-RackBuilder.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/delete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/dup-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/handlers-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert_after-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert_before-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/lock%21-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/locked%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/raise_if_locked-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/response-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/swap-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/to_app-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/use-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/use_symbol-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/%5b%5d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/%5b%5d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Authorization/build_hash-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Authorization/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Authorization/cdesc-Authorization.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Authorization/header-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Authorization/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/BasicAuthentication/cdesc-BasicAuthentication.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/BasicAuthentication/header-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/cdesc-Options.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/instrumenter-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/name-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/cdesc-Instrumentation.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/cdesc-Multipart.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/create_multipart-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/has_multipart%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/process_params-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/process_request%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/backoff_factor-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/cdesc-Options.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/exceptions-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/from-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/interval-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/interval_randomness-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/max-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/build_exception_matcher-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/cdesc-Retry.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/matcher;/cdesc-matcher;.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/sleep_amount-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/cdesc-TokenAuthentication.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/header-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/cdesc-UrlEncoded.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/match_content_type-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/mime_type-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/process_request%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/request_type-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/cdesc-Request.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/create-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/headers%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/params%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/to_env-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Request/url-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RequestOptions/%5b%5d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/RequestOptions/cdesc-RequestOptions.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/ResourceNotFound/cdesc-ResourceNotFound.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/cdesc-Logger.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/dump_headers-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/on_complete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/call-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/cdesc-Middleware.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/on_complete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/cdesc-RaiseError.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/on_complete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/response_values-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/apply_request-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/body-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/cdesc-Response.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/env-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/finish-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/finished%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/headers-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/marshal_dump-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/marshal_load-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/on_complete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/status-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Response/success%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/SSLError/cdesc-SSLError.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/SSLOptions/cdesc-SSLOptions.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/SSLOptions/disable%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/SSLOptions/verify%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/TimeoutError/cdesc-TimeoutError.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/TimeoutError/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/%5b%5d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/%5b%5d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/cdesc-Headers.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/delete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/fetch-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/from-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/has_key%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/include%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/key%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/member%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/merge%21-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/merge-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/parse-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/replace-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/to_hash-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/update-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/%5b%5d%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/%5b%5d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/cdesc-ParamsHash.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/convert_key-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/delete-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/has_key%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/include%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/key%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/member%3f-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/merge%21-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/merge-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/merge_query-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/replace-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/to_query-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/update-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/URI-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/build_nested_query-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/build_query-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/cdesc-Utils.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/deep_merge%21-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/deep_merge-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_params_encoder-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_params_encoder-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_uri_parser%3d-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_uri_parser-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/escape-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/normalize_params-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/normalize_path-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/parse_nested_query-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/parse_query-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/sort_query_params-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/Utils/unescape-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/cdesc-Faraday.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/const_missing-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/default_adapter%3d-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/default_adapter-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/default_connection-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/default_connection_options-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/lib_path-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/method_missing-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/new-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/require_lib-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/require_libs-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Faraday/root_path-c.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Object/cdesc-Object.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/Object/tap-i.ri create mode 100644 .gems/doc/faraday-0.9.0/ri/cache.ri create mode 100644 .gems/doc/http-0.6.2/ri/Base64/cdesc-Base64.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BasicAuth/cdesc-BasicAuth.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BasicAuth/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BearerToken/cdesc-BearerToken.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BearerToken/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/build-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/cdesc-AuthorizationHeader.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/register-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/accept-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/auth-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/branch-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/cdesc-Chainable.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/connect-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/default_callbacks%3d-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/default_callbacks-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/default_headers%3d-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/default_headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/default_options%3d-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/default_options-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/delete-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/follow-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/get-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/head-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/options-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/patch-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/post-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/put-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/request-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/stream-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/through-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/trace-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/via-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/with-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/with_follow-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Chainable/with_headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/cdesc-Client.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/default_options-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/finish_response-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/make_request_body-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/make_request_uri-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/perform-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/read_more-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/readpartial-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/request-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Client/start_tls-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Error/cdesc-Error.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Headers/Mixin/cdesc-Mixin.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Headers/Mixin/headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Headers/cdesc-Headers.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/%5b%5d-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/Adapter/cdesc-Adapter.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/cdesc-JSON.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/decode-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/encode-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/cdesc-MimeType.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/normalize-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/register_adapter-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/MimeType/register_alias-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/%5b%5d-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/OpenSSL/SSL/cdesc-SSL.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/OpenSSL/cdesc-OpenSSL.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/argument_error%21-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/body-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/cdesc-Options.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/default_socket_class-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/default_ssl_socket_class-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/dup-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/follow-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/form-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/json-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/merge-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/params-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/proxy-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/response-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/socket_class-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/ssl_context-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/ssl_socket_class-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/to_hash-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Options/with_headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Redirector/EndlessRedirectError/cdesc-EndlessRedirectError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Redirector/TooManyRedirectsError/cdesc-TooManyRedirectsError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Redirector/cdesc-Redirector.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/UnsupportedMethodError/cdesc-UnsupportedMethodError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/UnsupportedSchemeError/cdesc-UnsupportedSchemeError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/add_body_type_headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/add_headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/cdesc-Writer.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/join_headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/send_request_body-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/send_request_header-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/stream-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/Writer/validate_body_type%21-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/__method__-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/body-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/cdesc-Request.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/method-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/proxy-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/scheme-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/uri-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/verb-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Request/version-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/RequestError/cdesc-RequestError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Body/cdesc-Body.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Body/each-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Body/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Body/readpartial-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/%3c%3c-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/add-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/cdesc-Parser.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/chunk-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/finished%3f-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/headers%3f-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/headers-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/http_version-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/on_body-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/on_headers_complete-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/on_message_complete-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/reset-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/Parser/status_code-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/body-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/cdesc-Response.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/charset-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/code-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/content_type-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/flush-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/inspect-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/mime_type-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/new-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/parse-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/reason-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/status-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/status_code-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/stream%21-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/to_a-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/to_s-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/to_str-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/Response/uri-i.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/ResponseError/cdesc-ResponseError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/StateError/cdesc-StateError.ri create mode 100644 .gems/doc/http-0.6.2/ri/HTTP/cdesc-HTTP.ri create mode 100644 .gems/doc/http-0.6.2/ri/Object/cdesc-Object.ri create mode 100644 .gems/doc/http-0.6.2/ri/URI/cdesc-URI.ri create mode 100644 .gems/doc/http-0.6.2/ri/URI/decode_www_form-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/URI/decode_www_form_component-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/URI/encode_www_form-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/URI/encode_www_form_component-c.ri create mode 100644 .gems/doc/http-0.6.2/ri/cache.ri create mode 100644 .gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/cdesc-Parser.ri create mode 100644 .gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/default_header_value_type%3d-c.ri create mode 100644 .gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/default_header_value_type-c.ri create mode 100644 .gems/doc/http_parser.rb-0.6.0/ri/HTTP/cdesc-HTTP.ri create mode 100644 .gems/doc/http_parser.rb-0.6.0/ri/Object/cdesc-Object.ri create mode 100644 .gems/doc/http_parser.rb-0.6.0/ri/cache.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/InstanceMethods/cdesc-InstanceMethods.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/InstanceMethods/freeze-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/InstanceMethods/memoize-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/InstanceMethods/memoized_method_cache-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/%5b%5d%3d-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/%5b%5d-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/cdesc-Memory.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/fetch-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/key%3f-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/marshal_dump-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/marshal_load-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/new-c.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/BlockNotAllowedError/cdesc-BlockNotAllowedError.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/BlockNotAllowedError/new-c.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/InvalidArityError/cdesc-InvalidArityError.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/InvalidArityError/new-c.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/assert_arity-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/call-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/cdesc-MethodBuilder.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/create_memoized_method-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/new-c.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/original_method-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/remove_original_method-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/set_method_visibility-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/visibility-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/cdesc-ModuleMethods.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/freezer-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/included-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoize-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoize_method-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoized%3f-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoized_methods-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/unmemoized_instance_method-i.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/cdesc-Memoizable.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/Memoizable/included-c.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/cache.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/page-CONTRIBUTING_md.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/page-LICENSE_md.ri create mode 100644 .gems/doc/memoizable-0.4.2/ri/page-README_md.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/advance_io-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/cdesc-CompositeReadIO.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/current_io-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/new-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/read-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/rewind-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/MultipartPost/cdesc-MultipartPost.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Multipartable/cdesc-Multipartable.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Multipartable/new-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Post/Multipart/cdesc-Multipart.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Post/cdesc-Post.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Put/Multipart/cdesc-Multipart.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Put/cdesc-Put.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Net/HTTP/cdesc-HTTP.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Net/cdesc-Net.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/EpiloguePart/cdesc-EpiloguePart.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/EpiloguePart/new-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/build_head-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/cdesc-FilePart.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/length-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/new-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/build_part-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/cdesc-ParamPart.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/length-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/new-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/Part/cdesc-Part.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/Parts/cdesc-Parts.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/cdesc-UploadIO.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/content_type-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/convert%21-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/io-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/local_path-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/method_missing-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/new-c.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/opts-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/original_filename-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/UploadIO/respond_to%3f-i.ri create mode 100644 .gems/doc/multipart-post-2.0.0/ri/cache.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/BasicObject/cdesc-BasicObject.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/Conversions/Actual-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/Conversions/Just-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/Conversions/Maybe-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/Conversions/Null-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/Conversions/cdesc-Conversions.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/Conversions/included-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/builder-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/cdesc-Command.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/defer-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineExplicitConversions/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineExplicitConversions/cdesc-DefineExplicitConversions.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/cdesc-DefineImplicitConversions.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/to_ary-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/to_str-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Impersonate/cdesc-Impersonate.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Impersonate/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/cdesc-Mimic.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/class_to_mimic-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/include_super-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/methods_to_stub-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/root_class_of-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/cdesc-Pebble.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/parse_caller-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/cdesc-PredicatesReturn.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/define_method_missing-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/define_predicate_methods-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/cdesc-Singleton.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/get-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Traceable/call-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Traceable/cdesc-Traceable.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Traceable/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/cdesc-Commands.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/apply_operations-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/base_class-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/black_hole-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/cdesc-NullClassBuilder.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/class_operations-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/command_name_for_method-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/customization_module-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/customize-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/defer-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/define_basic_class_methods-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/define_basic_instance_methods-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/define_basic_methods-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/generate_class-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/get-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/inspect_proc-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/interface_defined%3f-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/interface_defined-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/method_missing-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/new-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/null_equivalents-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/operations-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to%3f-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to_any_message-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to_missing%3f-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/stub_method-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/stub_method_returning_nil-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/stub_method_returning_self-i.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/NullObjectTag/cdesc-NullObjectTag.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/build-c.ri create mode 100644 .gems/doc/naught-1.0.0/ri/Naught/cdesc-Naught.ri create mode 100644 .gems/doc/naught-1.0.0/ri/cache.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/attributes-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/cdesc-Header.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/decode-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/default_options-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/encode-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/escape-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/hmac_sha1_signature-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/method-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/new-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/normalized_attributes-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/normalized_params-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/options-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/params-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/parse-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/plaintext_signature-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/private_key-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/rsa_sha1_signature-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/secret-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature_base-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature_params-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signed_attributes-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/to_s-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/unescape-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/uri_parser-c.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/url-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/url_params-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/valid%3f-i.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/cdesc-SimpleOAuth.ri create mode 100644 .gems/doc/simple_oauth-0.2.0/ri/cache.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/cdesc-SynchronizedDelegator.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/method_missing-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/setup-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/teardown-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Array/cdesc-Array.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/%5b%5d%3d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/%5b%5d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/Util/cdesc-Util.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/cdesc-Node.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/force_aquire_lock-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/key%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/key-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/locked%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/locked_hash%3f-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/matches%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/pure_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/try_await_lock-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/try_lock_via_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/unlock_via_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/cas_new_node-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/cdesc-Table.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/delete_node_at-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/try_lock_via_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/try_to_cas_in_computed-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/attempt_compute-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/attempt_get_and_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/attempt_internal_compute_if_absent-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/attempt_internal_replace-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/cdesc-AtomicReferenceCacheBackend.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/check_for_resize-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/clear-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute_if_absent-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute_if_present-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/delete-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/delete_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/each_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/empty%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/find_value_in_node_list-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/get_and_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/get_or_default-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/initialize_copy-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/initialize_table-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/internal_compute-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/internal_replace-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/key%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/key_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/merge_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/replace_if_exists-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/replace_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/table_size_for-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/try_await_lock-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/%5b%5d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/cdesc-Cache.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/each_key-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/each_value-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/empty%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/fetch-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/fetch_or_store-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/get-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/index-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/initialize_copy-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/key-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/keys-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/marshal_dump-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/marshal_load-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/populate_from-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/put_if_absent-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/raise_fetch_no_key-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/validate_options_hash%21-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/value%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/values-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Hash/cdesc-Hash.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/%5b%5d%3d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/cdesc-MriCacheBackend.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/clear-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute_if_absent-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute_if_present-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/delete-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/delete_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/get_and_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/merge_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/replace_if_exists-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/replace_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/%5b%5d%3d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/%5b%5d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/_get-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/cdesc-NonConcurrentCacheBackend.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/clear-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/compute-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/compute_if_absent-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/compute_if_present-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/delete-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/delete_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/dupped_backend-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/each_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/get_and_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/get_or_default-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/initialize_copy-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/key%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/merge_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/pair%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/replace_if_exists-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/replace_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/store_computed_value-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/value%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/%5b%5d%3d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/%5b%5d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/cdesc-SynchronizedCacheBackend.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/clear-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute_if_absent-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute_if_present-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/delete-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/delete_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/dupped_backend-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/get_and_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/get_or_default-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/key%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/merge_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/replace_if_exists-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/replace_pair-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/value%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/add-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/cdesc-Adder.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/decrement-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/increment-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/reset-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/sum-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cdesc-CheapLockable.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cheap_broadcast-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cheap_synchronize-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cheap_wait-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/hash_to_index-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/next_in_size_table-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/volatile_get_by_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/volatile_set_by_hash-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/Cell/cas_computed-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/Cell/cdesc-Cell.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/cas_base_computed-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/cdesc-Striped64.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/expand_table_unless_stale-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/free%3f-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/hash_code%3d-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/hash_code-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/internal_reset-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/retry_update-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_in_busy-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_initialize_cells-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_to_install_new_cell-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Volatile/attr_volatile-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Volatile/cdesc-Volatile.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/cas-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/cdesc-VolatileTuple.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/compare_and_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/each-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/new-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/volatile_get-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/volatile_set-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/cdesc-XorShiftRandom.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/get-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/xorshift-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/cdesc-Util.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/_mon_initialize-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/allocate-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/cdesc-ThreadSafe.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/decrement_size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/increment_size-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/lock_and_clean_up_reverse_forwarders-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/rebuild-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/split_bin-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/split_old_bin-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/ThreadSafe/try_in_resize_lock-i.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/Threadsafe/cdesc-Threadsafe.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/Threadsafe/const_missing-c.ri create mode 100644 .gems/doc/thread_safe-0.3.4/ri/cache.ri create mode 100644 .gems/gems/addressable-2.3.6/CHANGELOG.md create mode 100644 .gems/gems/addressable-2.3.6/Gemfile create mode 100644 .gems/gems/addressable-2.3.6/LICENSE.txt create mode 100644 .gems/gems/addressable-2.3.6/README.md create mode 100644 .gems/gems/addressable-2.3.6/Rakefile create mode 100644 .gems/gems/addressable-2.3.6/data/unicode.data create mode 100644 .gems/gems/addressable-2.3.6/lib/addressable/idna.rb create mode 100644 .gems/gems/addressable-2.3.6/lib/addressable/idna/native.rb create mode 100644 .gems/gems/addressable-2.3.6/lib/addressable/idna/pure.rb create mode 100644 .gems/gems/addressable-2.3.6/lib/addressable/template.rb create mode 100644 .gems/gems/addressable-2.3.6/lib/addressable/uri.rb create mode 100644 .gems/gems/addressable-2.3.6/lib/addressable/version.rb create mode 100644 .gems/gems/addressable-2.3.6/spec/addressable/idna_spec.rb create mode 100644 .gems/gems/addressable-2.3.6/spec/addressable/net_http_compat_spec.rb create mode 100644 .gems/gems/addressable-2.3.6/spec/addressable/template_spec.rb create mode 100644 .gems/gems/addressable-2.3.6/spec/addressable/uri_spec.rb create mode 100644 .gems/gems/addressable-2.3.6/spec/spec_helper.rb create mode 100644 .gems/gems/addressable-2.3.6/tasks/clobber.rake create mode 100644 .gems/gems/addressable-2.3.6/tasks/gem.rake create mode 100644 .gems/gems/addressable-2.3.6/tasks/git.rake create mode 100644 .gems/gems/addressable-2.3.6/tasks/metrics.rake create mode 100644 .gems/gems/addressable-2.3.6/tasks/rspec.rake create mode 100644 .gems/gems/addressable-2.3.6/tasks/rubyforge.rake create mode 100644 .gems/gems/addressable-2.3.6/tasks/yard.rake create mode 100644 .gems/gems/addressable-2.3.6/website/index.html create mode 100644 .gems/gems/buftok-0.2.0/CONTRIBUTING.md create mode 100644 .gems/gems/buftok-0.2.0/Gemfile create mode 100644 .gems/gems/buftok-0.2.0/LICENSE.md create mode 100644 .gems/gems/buftok-0.2.0/README.md create mode 100644 .gems/gems/buftok-0.2.0/Rakefile create mode 100644 .gems/gems/buftok-0.2.0/buftok.gemspec create mode 100644 .gems/gems/buftok-0.2.0/lib/buftok.rb create mode 100644 .gems/gems/buftok-0.2.0/test/test_buftok.rb create mode 100644 .gems/gems/equalizer-0.0.9/.gitignore create mode 100644 .gems/gems/equalizer-0.0.9/.reek.yml create mode 100644 .gems/gems/equalizer-0.0.9/.rspec create mode 100644 .gems/gems/equalizer-0.0.9/.rubocop.yml create mode 100644 .gems/gems/equalizer-0.0.9/.ruby-gemset create mode 100644 .gems/gems/equalizer-0.0.9/.travis.yml create mode 100644 .gems/gems/equalizer-0.0.9/.yardstick.yml create mode 100644 .gems/gems/equalizer-0.0.9/CONTRIBUTING.md create mode 100644 .gems/gems/equalizer-0.0.9/Gemfile create mode 100644 .gems/gems/equalizer-0.0.9/LICENSE create mode 100644 .gems/gems/equalizer-0.0.9/README.md create mode 100644 .gems/gems/equalizer-0.0.9/Rakefile create mode 100644 .gems/gems/equalizer-0.0.9/equalizer.gemspec create mode 100644 .gems/gems/equalizer-0.0.9/lib/equalizer.rb create mode 100644 .gems/gems/equalizer-0.0.9/lib/equalizer/version.rb create mode 100644 .gems/gems/equalizer-0.0.9/spec/spec_helper.rb create mode 100644 .gems/gems/equalizer-0.0.9/spec/support/config_alias.rb create mode 100644 .gems/gems/equalizer-0.0.9/spec/unit/equalizer/included_spec.rb create mode 100644 .gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/eql_predicate_spec.rb create mode 100644 .gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/equality_operator_spec.rb create mode 100644 .gems/gems/equalizer-0.0.9/spec/unit/equalizer/universal_spec.rb create mode 100644 .gems/gems/faraday-0.9.0/.document create mode 100644 .gems/gems/faraday-0.9.0/CHANGELOG.md create mode 100644 .gems/gems/faraday-0.9.0/CONTRIBUTING.md create mode 100644 .gems/gems/faraday-0.9.0/Gemfile create mode 100644 .gems/gems/faraday-0.9.0/LICENSE.md create mode 100644 .gems/gems/faraday-0.9.0/README.md create mode 100644 .gems/gems/faraday-0.9.0/Rakefile create mode 100644 .gems/gems/faraday-0.9.0/faraday.gemspec create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http_ssl_patch.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony/parallel_manager.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/excon.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/httpclient.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http_persistent.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/patron.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/rack.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/test.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/adapter/typhoeus.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/autoload.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/connection.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/error.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/middleware.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/options.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/parameters.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/rack_builder.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/authorization.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/basic_authentication.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/instrumentation.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/multipart.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/retry.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/token_authentication.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/request/url_encoded.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/response.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/response/logger.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/response/raise_error.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/upload_io.rb create mode 100644 .gems/gems/faraday-0.9.0/lib/faraday/utils.rb create mode 100755 .gems/gems/faraday-0.9.0/script/console create mode 100755 .gems/gems/faraday-0.9.0/script/generate_certs create mode 100755 .gems/gems/faraday-0.9.0/script/package create mode 100755 .gems/gems/faraday-0.9.0/script/proxy-server create mode 100755 .gems/gems/faraday-0.9.0/script/release create mode 100755 .gems/gems/faraday-0.9.0/script/server create mode 100755 .gems/gems/faraday-0.9.0/script/test create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/default_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/em_http_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/em_synchrony_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/excon_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/httpclient_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/integration.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/logger_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/net_http_persistent_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/net_http_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/patron_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/rack_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/test_middleware_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/adapters/typhoeus_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/authentication_middleware_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/composite_read_io_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/connection_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/env_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/helper.rb create mode 100644 .gems/gems/faraday-0.9.0/test/live_server.rb create mode 100644 .gems/gems/faraday-0.9.0/test/middleware/instrumentation_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/middleware/retry_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/middleware_stack_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/multibyte.txt create mode 100644 .gems/gems/faraday-0.9.0/test/options_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/request_middleware_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/response_middleware_test.rb create mode 100644 .gems/gems/faraday-0.9.0/test/strawberry.rb create mode 100644 .gems/gems/faraday-0.9.0/test/utils_test.rb create mode 100644 .gems/gems/http-0.6.2/.coveralls.yml create mode 100644 .gems/gems/http-0.6.2/.gitignore create mode 100644 .gems/gems/http-0.6.2/.rspec create mode 100644 .gems/gems/http-0.6.2/.rubocop.yml create mode 100644 .gems/gems/http-0.6.2/.travis.yml create mode 100644 .gems/gems/http-0.6.2/CHANGES.md create mode 100644 .gems/gems/http-0.6.2/Gemfile create mode 100644 .gems/gems/http-0.6.2/Guardfile create mode 100644 .gems/gems/http-0.6.2/LICENSE.txt create mode 100644 .gems/gems/http-0.6.2/README.md create mode 100644 .gems/gems/http-0.6.2/Rakefile create mode 100755 .gems/gems/http-0.6.2/examples/parallel_requests_with_celluloid.rb create mode 100644 .gems/gems/http-0.6.2/http.gemspec create mode 100644 .gems/gems/http-0.6.2/lib/http.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/authorization_header.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/authorization_header/basic_auth.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/authorization_header/bearer_token.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/backports.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/backports/base64.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/backports/uri.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/chainable.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/client.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/content_type.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/errors.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/headers.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/headers/mixin.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/mime_type.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/mime_type/adapter.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/mime_type/json.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/options.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/redirector.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/request.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/request/writer.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/response.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/response/body.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/response/parser.rb create mode 100644 .gems/gems/http-0.6.2/lib/http/version.rb create mode 100644 .gems/gems/http-0.6.2/logo.png create mode 100644 .gems/gems/http-0.6.2/spec/http/authorization_header/basic_auth_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/authorization_header/bearer_token_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/authorization_header_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/backports/base64_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/backports/uri_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/client_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/content_type_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/headers/mixin_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/headers_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/body_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/form_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/headers_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/json_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/merge_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/new_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options/proxy_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/options_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/redirector_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/request/writer_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/request_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/response/body_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http/response_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/http_spec.rb create mode 100644 .gems/gems/http-0.6.2/spec/spec_helper.rb create mode 100644 .gems/gems/http-0.6.2/spec/support/example_server.rb create mode 100644 .gems/gems/http-0.6.2/spec/support/proxy_server.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/.gitignore create mode 100644 .gems/gems/http_parser.rb-0.6.0/.gitmodules create mode 100644 .gems/gems/http_parser.rb-0.6.0/Gemfile create mode 100644 .gems/gems/http_parser.rb-0.6.0/Gemfile.lock create mode 100644 .gems/gems/http_parser.rb-0.6.0/LICENSE-MIT create mode 100644 .gems/gems/http_parser.rb-0.6.0/README.md create mode 100644 .gems/gems/http_parser.rb-0.6.0/Rakefile create mode 100755 .gems/gems/http_parser.rb-0.6.0/bench/standalone.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/bench/thin.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.RUBYARCHDIR.time create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.gitignore create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/RubyHttpParserService.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ext_help.h create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/extconf.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ruby_http_parser.c create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/.gitkeep create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/README.md create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/TODO create mode 100755 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/build.xml create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/test.c create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/AUTHORS create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/README.md create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.c create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.h create mode 100644 .gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/test.c create mode 100644 .gems/gems/http_parser.rb-0.6.0/http_parser.rb.gemspec create mode 100644 .gems/gems/http_parser.rb-0.6.0/lib/http/parser.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/lib/http_parser.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/spec/parser_spec.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/spec/spec_helper.rb create mode 100644 .gems/gems/http_parser.rb-0.6.0/spec/support/requests.json create mode 100644 .gems/gems/http_parser.rb-0.6.0/spec/support/responses.json create mode 100644 .gems/gems/http_parser.rb-0.6.0/tasks/compile.rake create mode 100644 .gems/gems/http_parser.rb-0.6.0/tasks/fixtures.rake create mode 100644 .gems/gems/http_parser.rb-0.6.0/tasks/spec.rake create mode 100644 .gems/gems/http_parser.rb-0.6.0/tasks/submodules.rake create mode 100644 .gems/gems/memoizable-0.4.2/CONTRIBUTING.md create mode 100644 .gems/gems/memoizable-0.4.2/LICENSE.md create mode 100644 .gems/gems/memoizable-0.4.2/README.md create mode 100644 .gems/gems/memoizable-0.4.2/Rakefile create mode 100644 .gems/gems/memoizable-0.4.2/lib/memoizable.rb create mode 100644 .gems/gems/memoizable-0.4.2/lib/memoizable/instance_methods.rb create mode 100644 .gems/gems/memoizable-0.4.2/lib/memoizable/memory.rb create mode 100644 .gems/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb create mode 100644 .gems/gems/memoizable-0.4.2/lib/memoizable/module_methods.rb create mode 100644 .gems/gems/memoizable-0.4.2/lib/memoizable/version.rb create mode 100644 .gems/gems/memoizable-0.4.2/memoizable.gemspec create mode 100644 .gems/gems/memoizable-0.4.2/spec/integration/serializable_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/shared/call_super_shared_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/shared/command_method_behavior.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/spec_helper.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/class_methods/included_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/fixtures/classes.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/freeze_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/memoize_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/memory_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/call_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/class_methods/new_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/original_method_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/included_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoize_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoized_predicate_spec.rb create mode 100644 .gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/unmemoized_instance_method_spec.rb create mode 100644 .gems/gems/multipart-post-2.0.0/.gitignore create mode 100644 .gems/gems/multipart-post-2.0.0/.travis.yml create mode 100644 .gems/gems/multipart-post-2.0.0/Gemfile create mode 100644 .gems/gems/multipart-post-2.0.0/History.txt create mode 100644 .gems/gems/multipart-post-2.0.0/Manifest.txt create mode 100644 .gems/gems/multipart-post-2.0.0/README.md create mode 100644 .gems/gems/multipart-post-2.0.0/Rakefile create mode 100644 .gems/gems/multipart-post-2.0.0/lib/composite_io.rb create mode 100644 .gems/gems/multipart-post-2.0.0/lib/multipart_post.rb create mode 100644 .gems/gems/multipart-post-2.0.0/lib/multipartable.rb create mode 100644 .gems/gems/multipart-post-2.0.0/lib/net/http/post/multipart.rb create mode 100644 .gems/gems/multipart-post-2.0.0/lib/parts.rb create mode 100644 .gems/gems/multipart-post-2.0.0/multipart-post.gemspec create mode 100644 .gems/gems/multipart-post-2.0.0/test/multibyte.txt create mode 100644 .gems/gems/multipart-post-2.0.0/test/net/http/post/test_multipart.rb create mode 100644 .gems/gems/multipart-post-2.0.0/test/test_composite_io.rb create mode 100644 .gems/gems/multipart-post-2.0.0/test/test_parts.rb create mode 100644 .gems/gems/naught-1.0.0/.gitignore create mode 100644 .gems/gems/naught-1.0.0/.rspec create mode 100644 .gems/gems/naught-1.0.0/.rubocop.yml create mode 100644 .gems/gems/naught-1.0.0/.travis.yml create mode 100644 .gems/gems/naught-1.0.0/Changelog.md create mode 100644 .gems/gems/naught-1.0.0/Gemfile create mode 100644 .gems/gems/naught-1.0.0/Guardfile create mode 100644 .gems/gems/naught-1.0.0/LICENSE.txt create mode 100644 .gems/gems/naught-1.0.0/README.markdown create mode 100644 .gems/gems/naught-1.0.0/Rakefile create mode 100644 .gems/gems/naught-1.0.0/lib/naught.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/basic_object.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/conversions.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/command.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_explicit_conversions.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_implicit_conversions.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/impersonate.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/mimic.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/pebble.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/predicates_return.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/singleton.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/traceable.rb create mode 100644 .gems/gems/naught-1.0.0/lib/naught/version.rb create mode 100644 .gems/gems/naught-1.0.0/naught.gemspec create mode 100644 .gems/gems/naught-1.0.0/spec/base_object_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/basic_null_object_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/blackhole_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/explicit_conversions_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/functions/actual_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/functions/just_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/functions/maybe_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/functions/null_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/implicit_conversions_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/mimic_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/naught/null_object_builder/command_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/naught/null_object_builder_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/naught_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/pebble_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/predicate_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/singleton_null_object_spec.rb create mode 100644 .gems/gems/naught-1.0.0/spec/spec_helper.rb create mode 100644 .gems/gems/naught-1.0.0/spec/support/convertable_null.rb create mode 100644 .gems/gems/naught-1.0.0/spec/support/jruby.rb create mode 100644 .gems/gems/naught-1.0.0/spec/support/rubinius.rb create mode 100644 .gems/gems/naught-1.0.0/spec/support/ruby_18.rb create mode 100644 .gems/gems/simple_oauth-0.2.0/.gemtest create mode 100644 .gems/gems/simple_oauth-0.2.0/.gitignore create mode 100644 .gems/gems/simple_oauth-0.2.0/.rspec create mode 100644 .gems/gems/simple_oauth-0.2.0/.travis.yml create mode 100644 .gems/gems/simple_oauth-0.2.0/.yardopts create mode 100644 .gems/gems/simple_oauth-0.2.0/CONTRIBUTING.md create mode 100644 .gems/gems/simple_oauth-0.2.0/Gemfile create mode 100644 .gems/gems/simple_oauth-0.2.0/LICENSE create mode 100644 .gems/gems/simple_oauth-0.2.0/README.md create mode 100644 .gems/gems/simple_oauth-0.2.0/Rakefile create mode 100644 .gems/gems/simple_oauth-0.2.0/lib/simple_oauth.rb create mode 100644 .gems/gems/simple_oauth-0.2.0/lib/simple_oauth/header.rb create mode 100644 .gems/gems/simple_oauth-0.2.0/simple_oauth.gemspec create mode 100644 .gems/gems/simple_oauth-0.2.0/spec/helper.rb create mode 100644 .gems/gems/simple_oauth-0.2.0/spec/simple_oauth/header_spec.rb create mode 100644 .gems/gems/simple_oauth-0.2.0/spec/support/fixtures/rsa-private-key create mode 100644 .gems/gems/simple_oauth-0.2.0/spec/support/rsa.rb create mode 100644 .gems/gems/thread_safe-0.3.4/.travis.yml create mode 100644 .gems/gems/thread_safe-0.3.4/Gemfile create mode 100644 .gems/gems/thread_safe-0.3.4/LICENSE create mode 100644 .gems/gems/thread_safe-0.3.4/README.md create mode 100644 .gems/gems/thread_safe-0.3.4/Rakefile create mode 100755 .gems/gems/thread_safe-0.3.4/examples/bench_cache.rb create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/LongAdder.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/Striped64.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/LongAdder.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/Striped64.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166y/ThreadLocalRandom.java create mode 100644 .gems/gems/thread_safe-0.3.4/ext/thread_safe/JrubyCacheBackendService.java create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/atomic_reference_cache_backend.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/cache.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/mri_cache_backend.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/non_concurrent_cache_backend.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_cache_backend.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_delegator.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/adder.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/atomic_reference.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/cheap_lockable.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/power_of_two_tuple.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/striped64.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile_tuple.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/util/xor_shift_random.rb create mode 100644 .gems/gems/thread_safe-0.3.4/lib/thread_safe/version.rb create mode 100644 .gems/gems/thread_safe-0.3.4/test/src/thread_safe/SecurityManager.java create mode 100644 .gems/gems/thread_safe-0.3.4/test/test_array.rb create mode 100644 .gems/gems/thread_safe-0.3.4/test/test_cache.rb create mode 100644 .gems/gems/thread_safe-0.3.4/test/test_cache_loops.rb create mode 100644 .gems/gems/thread_safe-0.3.4/test/test_hash.rb create mode 100644 .gems/gems/thread_safe-0.3.4/test/test_helper.rb create mode 100644 .gems/gems/thread_safe-0.3.4/test/test_synchronized_delegator.rb create mode 100644 .gems/gems/thread_safe-0.3.4/thread_safe.gemspec create mode 100644 .gems/specifications/addressable-2.3.6.gemspec create mode 100644 .gems/specifications/buftok-0.2.0.gemspec create mode 100644 .gems/specifications/equalizer-0.0.9.gemspec create mode 100644 .gems/specifications/faraday-0.9.0.gemspec create mode 100644 .gems/specifications/http-0.6.2.gemspec create mode 100644 .gems/specifications/http_parser.rb-0.6.0.gemspec create mode 100644 .gems/specifications/memoizable-0.4.2.gemspec create mode 100644 .gems/specifications/multipart-post-2.0.0.gemspec create mode 100644 .gems/specifications/naught-1.0.0.gemspec create mode 100644 .gems/specifications/simple_oauth-0.2.0.gemspec create mode 100644 .gems/specifications/thread_safe-0.3.4.gemspec diff --git a/.gems/cache/addressable-2.3.6.gem b/.gems/cache/addressable-2.3.6.gem new file mode 100644 index 0000000000000000000000000000000000000000..254dec8536876fe21e129397d54cc1ebb57e3288 GIT binary patch literal 98304 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%0A*n-jdDr^vxW; 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ξP65%bZM{Q+ z>$T3BPj_tQRnYij!*TwgvZwLTjUvyH`!mi?bHBUg4bC3l_5Z2`0M+v9 zfNCnBtBvFxKYsj!&Z!;0R_~nimZ+a6Ub^Ah^-Fp71;xqp}nG)vkX%%JI_g*WmC_|cGZy$&e#&=PICgKT+b1f ztd7CGE<1zi&Y`{Me{FyB8ilPk{^UkWuU+7bwmVCyU@2LCQyQ*W!mHJGj4E|_uWC`3 zUgEXjlUz7|-RYT8=zqf@EqtQLs_wZ#qOvip5hrxsCaU<8cdLJ1L6gMOHpUa>3{}d;-D zq3qmU0EL(FnT6+yt0YDvP=}&$blai?RWq$LjB)-_L&>?PWJrAujQ4)}YlsaZ zNBZ)8?X?YkxaNlmTyg-DpLts|?Hwrp__2q+4H?S%Nat=D zz`cq6Dtj=_E16}x<9}e4{9lmhpI)847vUk~EBAGue8YDW&KmLJ#n%sEx}Y06fwG0U z@9g7J`G1z0t|%Su>bT-Q(h{tvwB)AjH{!?Nz0Rl#7zLcyIDHq&uXOTy^+p{bdG-t6 z6@5X&Qx>PHcIw*O{0zBw?T7_1!#i~#_p77$6=xU7qT0jT+C$sgBil<-i?_{*hwh0s zDv~pU5#i&QucJpuYP+pdKG;4OeAMqmNqw=x@)AywCG|}Xs7j>QNsgvkrG2hW6F2>2 zfAMb-?@oCRd0lN->{~WY)_}y3+`N_ufJ0+G6g$KqvQ9@z( zu+3m4SV``B%1?)k%cvi&;i@Lf{j%obmp=#2LNxfW!Sm=g9$?^QGQT9m#v|bvIf$s- z;gheQ;uefqN(U_Y-0maNBdeJ^yiXPV4f=;XHGUI;0KF|3YSO^~eQ0|JSp?KSeceVN z!PIY@Rh)#)geXwVhzOmK6XaYaK*DDFUzP+tAwFV63T#e1{Kajz5CVO_3(tdF2#KD( z_+`@uGJVE&_T~}EH1)f(Qs5EcCCMW|SFt8CX3PRUxq>3BrNNEF!$y5MHeL=qBJ3nJ zCPdtC53^2|JO=pa>?RpvYUJqbF%g8a;4ehOO{4KMF3`C`Hy(N~8G0`cdha-gnEs_6&$AEDvkcEO9r)g< zPk;7eZT3QV_M#KP5v+LIZFB!(b02DR|2YE6Tle3G=psn<>;+#0bR|ip5Ta59nJI+K z5D!Z}1K&#~Y`lDVp7Fug0XjTg+$66;B(D*sT`)b&B(HoVuWTf*d8Spjfl(2GpoqYj zh(If%%0I@1klq*k2hWFI8E~LA5%b@zLP($#xK|eZ_WY$AH|E=3?@m;p9h~}v_)e5K zuY@=@nJjQ*d&cq$d%R5(y{&iVho+C4gR8jBWna#s^=MB!>1`9|y;SDmoWvznhAOpv z3)32uZlzc)F_&?h!@hUW+oE`H=apH$Nca{Kq#>V2>&;V2+UR$gN!ti_8B5#vb{R<9 z5NuXaH^CcKQa90TmQw?9K+33_xHn6vo6wAkshgNLi>RAOjS7KIO`Qkw%BJFQ@1$6V zRe=0I<H4Hir0C=6P{I%i^4N4JT5U?be&p{{us#T+J(8^sL2qd+zNVW%Rf zO(BXqx=rXq4Z#izbqz|CU6{@1!Dd+JYApNcHntBnxP|1{qVR>KSf|l#VjpSahii)Ot2nE&U%!0_ zV8%W`URrWuRr-wmhP*W6M4#P4tpsBb2)4}Hr>=%s?~V{2Y9jjfZX1cHCiNT7AA-IO z>o#?z&cuBfhXRORb_oqDoWZJ7Y33qL9NhX#gzyH>hi`=2NW^FF=OTW63nKmA#;wGi zvo4Cx-eaHX5_bLt2OQ}a!D>u-$UI;jHuG+c^81R~=z-&fFZ=l!91?YV zqaL=>S%ENfLOT1_3s<9za{H0E^SIJmxw=DFMZLNMTk}f^d_sLHcj@||rfccClpq?A zBKrcQU}kb$aJ#bw_UME>&Qh{<7UmiGol8`5U2t!__foRU#_fPgtZYCf{QER@hr?rj z!M*+Ir>%b}+4}l{v5jmI4uO^G4kF82`zfTD(2-o1-P)Hhpx@Gbw{fN0-B#hfi1UC* zb%*;iPocdJDey&)v%H?Po7{0Qlbf-YrIcNB;+S z<#zAcaZ0!GII{cC%I%Q!e3x^(}+&+Y?SkGuj_ zEYt{GW8}X)1>kVKABBMyzJW`O{4VF`f_pM&FaAJ_?!fI7()K&U|0NGovNcY{UB;DU zZYcpwmy!{2*yyfS*&>XzQsyqB^db1r51bZso zyjc-uulCvyl0u%hPR(dS-y#jaYmBn53=MNVTcQmZH?d3_*G~kFJ6*puO;me|y|I_B zf8Brc7)Q5!rTkyAd7{^z@p@m>DFjPd^I2W4N;yk@Sqk8k}6^<52J zeou?6^|jcew)^ZNO+Drh27|}{M>cIzqpqoCYzj; z#nw3w&XYctc#+?8icN{}+O8`4OO2O|hZ@OBbHY#&W+!|L4QmMJVpW`;S@#acFZM)~%iXU7l_sr`DYH(6hzqqK!oci!Tk-n(`>XIg!6mCbLCv zvZfL#KN^Jw3ur2J9hi-l&1?pH1dZ~bsKj1_hvF$CN~y$morNf%zk<%q^TI?>O3a9c zhba#{>=jAss*tXhxM`CM=~dN**2C&Ucl&*EQKS_M3m#ZsWc zz-)E)j-}~)>e+4naVOcUyKPvoJu$L-(5p7B(yB*g?pfOhtR5wh$*@ydpplx z@jP2{Dsr>DFr3y`C+2(E-oQL@iX9er*TUpArWf%L2PxtHqS3U@h`%SYA*~=6e?1&K z3I*>*c9te2+%1d-4FzPuLPKAlkT6kOcV?jwZO>K}i#-8UuOxHhO@fP&AC3OH4X8S0 z--S= zP^ozB6Mh(1SrwRGiPu z!!yrbv%amJHztH6wW41LjC5ZN`}FP#X~Sy2{42bP)9`>3!5%&0*uVQzWnz^1Hz1!I z#UPTk%jYf^tv*6zT5}JXBUuZTr}>bz>rY)_Rr}Y*aL$wDjy_K1=jQL@@6fB|3GmnR zns&(hemM#lw>@t+>ZgML?nZe|W@N&y$m_tj%X4AQ7a(Y(zkHnT?5DtRWd-rh zkxG})IF@zMc)+#cjK7q$3D?R?)9q6+oq7-)HUHr&@VoF2+!qCoX`X;{(Qdg|;Dl+5 zdkn<~RQK4~4^gwvh4>#O3?iPv(qD2}7AQpw(81u^msE8}n6X zPucwVMeJxBOaL3ooBf=FYzevh>KcXNltrlUf!$C>ZRA-^%6i?%FZ3>=Bkk6DDEx?cXwxTcXx-y-CY-VcXxMpcXwTEfddPR%i^#nB&l1ul|1C-rYd#o@0XFT zk^bgkrg~=j<2slB+lDRuV<9H(XBio?_a%;>%T$FW@rVxFvzsIR7irsk7gz{da|9#r zx`sE9$Y1peRQ2+430l`TzFgb}*?s#5(tq9h9iRah?3j){uwg1TaakG{v6A=L>MlWk zLDn|=!ZTk=K3^fW5C19&VaRP&vQF(63^X2`e+hpqb?=a1dzP;=Z**@?0}2I9u) z-RK@M1$%&FSzFv-W;`VWyuZ^56kP{CHG`>59R%tPUJAdzWsj2izmKmXjb=vD9n zMZ|Euej*KR3BGKrE1xs7A`R(fSguo$dSqk*T?8!dUw`}9ZNII#%{Ml}b7hS(ruq&K zEx|_=EiW){Wv|%FarssaEpG8Qpwje)dcgF~u*mhFA7$!!Slep)oa)yhCoG^jD65zl zw-0J{BqA}NeZYtE7BKr)KR$6%YAzO2-cm&4R`;{GZ|!82{f?|eY-yINNho*~ zC2RY@*NEKg_iWn*)CU!YIHz@m<`G%_1&~$Y(1vjY^%2Xry3dg2N`!cH1njeIXOuby zWh=3NLT!p6tKo>Rp_gp0AH3A@nl2h^f?eP&_VFGtE=3VAh~$1duvur}@GOBi$veIx zX+f)80#Ts+Q%(vLx&x)BxAT4mTAfIN1|2?GqD5%Gl@DPSFgQpHu3zOuaD+Id=g&X&QvW#?UYT322e?)-+_w1j%v3|aH9m~-`#e#XOf zo`NkO^Ri*|sTx1Zgo8&xdd}EVf=Frz68BL_du{a_d_eSHV|~NI$(OI9aeoTb znF|udu!gmn*pY$7{zHOECo~bJT-l18&Yy2qRS(?GXOvl#7-~mb-YDUEiVd-f#yX|E zz2L-^`%oA4>3?(6%{>^pM3Aefe6-|{0dm%U!}Z5D(f%N=5RKM_W(S?K&qBnTxX1l; zBKdLU{%m|v`ngAR5q+&0Gr|XRHPte~ED9^=2Lp#2|K%&Bhufw~ED*G_u%b8v8@0?_ z(+!sM`ekskzpgnZlPP3>Bi%o@SaFM-DwetSFv<#fK~S2m!iIo3xBw7wEtJ&FAvMj8 za(t5&y(-MDI>C-DJa`-XwR7J|=^pC}zb*d@N0jI9(zE3D!92$;@WriYzc$E&gZC1c zD*cXh7%Ak+Ud<{HSNeN@U42%P!pgTrp?rI4_lv+?7{1ziS*cxxHhdsBRI&I&U9P^M zfO$Agul_YU8XF6AEum}o7ekME+l*P&QUe9C>T@Z8ev6L@u}PYirq-BJ=dy;iLxvM6 zR@LD98+cuQB>)NdZBgK|v-Nf+1lnKSf6YEZb?~NIX$ezMF;%_5BCRq{S5ZE1#g)Ig zJ+Z|-#VtmpSP~kPH(Y|sGhWhCVgXy?Tf+R-m_|9eFMyf3VrpoiXYo4l^7BtrbBmT1 zb!-8Cm4ovclcvuShYt+CE^Ge`hsw-QP&u*IZ?viiIr1eaM|QZv)Xz$cUxm@gFB6}_ zom!TcgOBUEpMg%o{~9}<(K0trGN55*g3^IJkK*P&ZFIz>NAYb6qag7w>xPVyC8cQs@Z{So^QI7KTwK(SM7finEI>aq%M1-SmMTLcx?WqO#xBZ%4WU;Fe04s~wf zPBIia?_{+8u#@M8spg$$me4hknmN}Xcx7>C3fHBkUDGqXoW6->4~tkVQF=emOymrV zYt&9HwWFF&%fL@J69d|$eB*vnBT<-pY-MYGZR9LS#*FYfCHY;IHxgR)%_u zf?FfvYOLDch4W=D9_%v}8Xx=_iGok$)s=8z|6PH_A&fy`9+-h>h(OUxP<3H=;T}xU zw-b=o=`*OYf$`TC$m!d^*xo@quJ-;-3@6>Qd4Nh(Ruwg}M%k9?hP4WBj~;AOfeOWM ziI}i4pB9fkiV&^*gsSoo?PH#(CVIil~=2fMfIK-lISwysyB%fy;O-nG$u_$4vZ) zvQn;NZ+}($_ow{Oz2jy;IOfPEa@+zfT!_HjxGnTAq#?#z^e^M?!ehmzq0)aJTMYj0 z(=r2GNac}y_J`Mol=!P6npb&}Qw1iHsa$Uc>=VxA_{y~~^oWWtgBylIE$9(hPH!%p zK?vZqwgraVYv)w*YP@Oua|+sKwUzSvRac=dk4>}newho&^=%t0h8e7Ut-g5@CTy2Y zk8&-hKXl79+rpc2?h8oz2+eJ>!xY=C_4O~jHnr>NZ2+#`O?*ODKKRmP`ddc*0d@ga zjsxHE?pW{fu5eop^2l~-Ra}Y(v-{JO)b;L@U~QzdbYVIDM}(W`t8{hBYfA@0IgyDxGU3lSvAxKSG%K}OC0`KmKW2Jyu zcBvRKpAZCbpLI+5)2S)OeL-u=Vr>ql$;?j8{UPyctj@y)Gd==TRzmYq=0gX#xO6<~ zug>>LB=)CRM3E-2Es3q3z0eY zH`TUWZg%d2O!qt3UmX@57q^lH#=MVFyY^gmI$<1kN(aEhL^Y6Ri3_Ui^=TL#&@4&4 zaj{7<`@d6xX<|y}5+?2~Pr!K%)t3rh-p2gUn8UaQ=4mYaT2nfe?0?_MO4`d9wAyiK zo9EkZd#7ajIZK(}1dl<1HNg~AUi-Mi>LytVhV7_g><)DkRY8* zEY=j}JH<_yl0SGOlXgI6hCzb33f)?i-FrXqyJfV(^k?oxttWF!3+I$U-9;(@vhwhN zEaBalD^#$@Ft7&B4(K?D2a-sOpuE^1pTgpk`~ebuH6{(v6N_$Wg`}|P-&xK-cBOZq z!>ti361Al3xd&M<@L4ZpDfLhw3_i+oUUUcMH&7EEeuYsLo6@qC?v0v4VUMCg6~RtWJz=5Afs2$Ef}qtgJC< z5r)4l(ptAJ`*El%^(-=s&@5EA1kNG5ju357Pj;l57i#rg?-Q=tI0Jpja({<+ z%e1SPtZ4^)CwWL@PH7n|ab!&G*R!>Nyx7t|bY!X=d%GBd_pSbLzX?oVnkm!Jf=pST zXwY#*F~=}pnDEE~rcBm@%ptH$yUPgmhg{8P^=EL8)7x4~z*WgR+oUJDJT*CvcU=in zraUVAO0>X@MfspBBlnC3TX(^jA%H1(PwwSmC04=F0?^BD6&)usEJ%6?wr<&Q8E_N# z$bFP~lLDpT@(^iwKTtkteaB_D_c!4(s3Cml=~6UMU~0qXg@xbOHw?WVDVIzTezTAy zmC8bbD^uj@;EAy9maat`PznyHc*61dO;-XU>g`-E1vfQ|_OhYlp{OhSb==%#F@>;4 z9pwOd^=o2BYQA9QgknNUKsug5pb3@+crbPF79&;+>!7g3zbYK$nKp@ZeI!wT%bZ%S zDQ{SWVl@Pzlsm)pgbrj{>uEtjGi=PUstvY+XiPTsA$N(Rw1yCvsHYcvrMx;wY)Ze1|?%WyJGCGLCd3VzVo}p^PLK#OU^K@2aa8eO>VT@;LsP zkVZdNjD?zeYZt@XL{wh0G;0{M%>+%sN(RwxWE4Uea;`~9Lsw|YSeTRZg2gUC^4+pL zb85xcYs7NU#5>VJ1>@ZQAUAW7`AiV}y{gIr-6I0e97YJAiOVA;!#t~imzdrTg;*d; zPz}ZkQ~a)KvH7PO0y?DqUC79JXb-Hk!m=+pCXE(<{0}91L$bv_-J-&RFk?3>*Ob8& zZ~knh!yr7Pn#3^Ps<%?{)Vu;h977HBRIu_1(xaGh5;wW3PxUZgj4`q*^T~MzO7Rq$ zQoW#(!-*xjgxcW38k2rxU>|8Ff_r? ziFk~a?P8S99|Kkuh|;sB5bB>X?W5)5eRQ7UNv76NSM6t1iPqGbWJ^&fC7iJw2?K9P z`3_f?gg2hO-c_ns-US>G>;E3Jo2i;fA)Nh?dBGbbH-X|!FhRq|QYf>nCS7P)9Lh1? zdWVOdV;FgI`rT~bixqb1Z9|r_ONr92VCEuogR`91)0SX?)bmRR?q$Nv_A$@THmO=< znUTnE=+LTUdnX1x0fr`oTNqvR?#V~koGto#kFVWKL1iS?rfReHcRUzjo+V+qsdAZ5 zaZHVLVX17=0=5b=NuKZ;q4-^}^j>N>tr93X!E@t;QSd652!Y7F(Fsr+%gDt$IP2jI z*7r#=XxS}DbkIqVe|4)z*Tb2m0udR4@DVMvibR>yd9uIQh%kaDX98et7l78RP#x%4aV_!oluRf=?vWS> zFEHLqBBon&BJ4ENOmfa*aKrLJm|myLQVi&_)3cY1VGs~MP@sB0M*WnJCVTssnH1c|lAA`AkVyp$M(A?Yo0O`Q7h< zTAQ0rzm5a3wK3G|9+!nu)u}S}uHdn%^6?>F2QX*xJHUc*9Q4RqRQa!6PS;HXg z4L0nkQcX>5zEhW>=9uq1LQU~2*k!5Vxx3>Fd$No0$6;(!K0b+8?>O62@`yS-&VHa` z=!#7@r(=>hXT5jj?3jx^hOB!6fnaEl3;lU^4-wU`8bT$L*CE z?-s;F%cRzEYuTPA%mS`shaw(LMCj`4Sdg2un(jAwvc#>)oG8G{-&|J3ynLB?<4&oU($<- zRl37-#_3LD``s4KpIiB98p28G0C2A$;Anu{w-Hw+h$;UAH!#P4P)rPeM@ALTi%q2{W)6%{&C&;G@NKo0lAdRJG6SnB)S^; zIJ+7TBr{8fxmr|Jd?3@Tm=%Y_tJ#O+l`zdlDG`(+A*#pz^=&Ob%m}S>DE*6d8MT`i zf%5fd3M+CW+inasR*$Oc^0dC44Dth7ikK1YJ49%jj_+f;16wrWy}rYO z@#YLOt_gH~F3hgF@~*%61!5N@Qoxgw{8|~}`?VMKm3pYJ>%)8)yxVW0kN`(uGCxJg z#m*0S+IVD6Q%$gtu-!&`utR}R0dgbX|&cXQ}Of9p$lf{ z)_wyM&Zb%8qYo@{&?2(F@B0MnVG@)$cse%erpd;U_0OcI>@ZoZ!Ts_PH<)CTh`|c( zB0ZDN3z2h4>!UP3ybw+zJ_9JX51R_J(VhL_ul<>O>C%i| zgBW6h)7_L>QiXd)#p$F3%L^Z12oVo9OB{U!>yLq1Ho-BeW6bU?1et)7!Ph~Bw8d|7 zEG{DAkRhzeg0W$_<8NGty2M}3O?I6znPn_*n~+*99St4KZK#&!U6qt!U1!ApD267k zP&NDG;zL^2%D5h78GqSya+IW+Ph-oNm@`&n{sf5Kmf$;?LNy4vsiHq>n2{c(qDQla zcwOXS({irjhd?5*kO0dEliA$Ec|1hzMJ<=j^{1$Kwlw$B>_b*xBrcwcPDrH{+@W^Z zWTXr;BO-O&G!!T(#Pyhn%5gnX9WDJ!GCh8tgN}k0c5j_dtaB9%^Kwv;&QwMn;a~jL zq!AT*uqt!iWQa*1gpi)0nGqOw)Wn&@6{VOPsVt^TxEV_8SfS!v8}gF8Y~>FFh1{%n zNE9%$3r6I%0^e3!TU0`%@(=tfln)LmxqM80HR9EN9PlD!85hELk;xtj#~E8vU$gpu z4ydxZTY3d4-F)A)!q2H(z-OB+nI@AHLmpy#0kPzWae1MQf+|ml)CggaEnzm;c_r;y z#!TYM;-I+HJISIXx16VUYrkN)(-$SuI~JKJPKGgd>x~SU+O{=huuYT(_SIVy)?{W3N;;W7M9=grUVTd zW~5U?)=N@c?b!|@4=OfuhQ3%AdbaJZj z?HyY*!yg0|d`SwVUB>wbY7@9()D;XSf;$4hPpf9(>Dj6wya|6&iLUR~P389m=#JXa z^v%r?A`9h+4E*qOY6|Q2SWl8MfHyR$FD@AKMOtlT*Wi|0WRQ$txdJiSPV%#JeH8VF z!711H1Xc-a{DO?V-UyLqr`~1O4tP2MneV<*N@_j^E6F;!MKI2}d*r?ZT7(}(ieA(J zy}xK2JW#z@(D1v)*|xm7+Nd{47?i9q#lpDlllmMjqGVl}N+oq(78M(R-$X*kAce-r zOyo(du^#OYdrS>)WB1VW%VU3xt5)g{*s^=;wgRr4C@)+yKt7-c7-CAME5+|=0-lT; z7Fp4_DlJ<+jm_Wo4Ml}!BP*E8astsfH{vU{MWT-VM!~|oEOK=ud+mNvtYbU7oy?3w zku@T34hM4isr^@mi73FB`hXt|zS6PU@x~8vkWw<; zBh3AEU?zn|WzNvSKVw34nRI7cXCTA)D9RVTb0ab6OD%Txw5Caq)wZ*d?M4J?L=N9R zrfjoFJPbofup>_wRAVM>91;85eiSSxNXA}j;2@Yrr(dA?iWl+2&RtX|?S!C*upZ0m zB&1!PsYGC4jSQ>Bp32aSRJG6crl=nG`gLzZUZ7=*NLd68V9-n?(d;CXuZc-7jzwV| zHN(R9BGXOOlXDUg@wbk+XAC#SC`6r&&V-bGBJkj+P+5Cdxv7BfAilF{OmkQx2?=#9 zRl~0!_J4)sJc@UqwNimZQ}KyDrSP7TjDf5+UvkpY(VC-@cf;r$sH&mvAOxmQ_ zucP;lq^y(@n}Gd6y+YO6AtW{E6w0H%A(~J!-(oVF7RyjKwcGAWbY6xT99vIkl&GDn z+W{jL>FpU2Z2yY6NDEJoosO+buS38tMX@K`4J}&N&$A@alc|Ne<|cO|%<^XpAG1;5 zMs^pGqHrN}4u%1{vPv^0q)#je((}4)ODQcia>NFBO5?3WF}#~w=7MbQRFfc08h0=) zvrqv|p*$=Ri*M;e$$ttnB^id%?=<0^yEbl1PuMXKO73|4~^_i^h8y{zg)g%D`*k^`DX1D zcykP&JQLcV8oJjoW#eQ5E3H4-#GUxunecNN2rM1FZdi&V|AieJ(D(B8B5*!U;o>cT z9l#vRXq?>Qo+oLIze@S;ib;!}ot&ffp%Qj@PlyD_qnh5KrRmPA6fGlCCQGsKOqw+# z;}hh$p@azDa~MVq7q@RFc{POFNhE>5*|3EE*{G|y^r{P&KH1C!1 z#n~oG7_5qQTOP46#hq7F5tY%GoQD(6H!0#t_&BB*4z~f;?~7il9g3ZWxkwkFulP?4 zj&Foy6t7L>h%?-^-Uj=nPog=Y zwjT;QCt*@ZYDvW{6OLs-9@1-EeS+sYGn!3E#%gcExs*`(aD0#@NPQ=oN zC4-Hig<+dkY6;@&Dm@FPCDh%rWcQeTs1C%FUvx_5&lOK8R7vbNg}0^A3H`Uli^;*w(GXA#v)3qVliiIX+AI=k^X)Fi8@79T!r%6MhBhi zsTExoU~yq>Hp1iD{RGXL3KT~9CCgi`JE0-#=U>4KLEwk3~cZ{5OHepo- zEc%-GvIxI!TSc?hfrx1Mp}*0~xqa%P;u}L$SWo{QVj(&jW->W=lTw3jFPZvVgOyT* z1Hxre^!)0GnJw;Q7s(yZ+?_kB(WE4~{x6k7!GLSo!6Cjy9!)Iq6jfiX48LvDSbq1z zkT`GJ1@*mw*0HHqDpVC>$4eK;V9r@4?An#+DX3Shvajg=2i0yDtem%kZ82^NJyF~2 zjxy|7^cCk%7(FGSgoMlq{?(XS>||R&%R#8}C%6bgeIIuY!u)aqXH<*6+?LcG=Ccw^ z;Y5iJof5fn1P|lUG58NgTvJnQz~1plfzshao*Q;0uRO_G+GnBxQ(Jr-9s?$yTv?>_kz#5*w@{jntl!sbjQpaE67@l}&WnB%;gVg7 zow3z{_KU2EOgtD@NcDLHzImsj;#}!Eg!GM@XPY`X~1NmA8)xAXvOO2e2i72)PC8h?3K-#K`GhO*XD*{qd&x3 zGQ$g0+BVrC^@DvUQ%j|XzqDoGooF}lM{jpeU(197Y(+Dcc2Bj2HtB;T(+iG@y5HNv zYNUTz+UA3#hhxQQBE@{*v|G<+NboM)QyaRhTVsqb9WFww_|ZwlHhFLG_kl9({+#6 zZEsn2`i>V$C8@gV-k-L;W4aAVhhz4BI5@%c+nfx2P#EbCd0`oIB+A`M38-2=k`bFo zAE`D)i+;y+SW&Ow+z|DH3JL2d&P87|0Y+s@|x>Lu~8E?Oh zn1Q?DO{EP{;D+B1>R<5&I5%hIYE5T%{(F*Frhn))BA+)P3D&t)NJh|dm)`x>uBiWd zgWhvYb8e;BWC@^YrLGq=jB;ITEH6b3@ATra{TJcdi+NFTKu@PEk;FvA~EuAFR$etJ>QC0cY59q z4#NfCH!uXNGjjr9t8jXw_f(cc`36FROaj4*hEnFokndE2nZ7q2Q4s$TWC?yY&}vR* zlmmlMZK;u4Ly}}0?f}z}%3~1nPKm2_J>8&H{k}(9Ig< z=?<0w-px9DlZnI*M8a%Uk4v_@Zo6p8j2Dhx@7_0O63k=NJ6qNTmp?v_A3Pi{zj>W~ z^IU8AoIuG5s>r(DB{=-MbFii_`H1?O0r`mO)S50VA%1rx`KZ$$G23wGUi(T=xT;Q7 z)}QlOz;lU?N+C4*9M+LJ2kBEj+X~n}wHEgFeXD!)N5j792*yn8L>=_(@eA6Fz8Y!+ zM3V;%Dh1IKAHFyBJH1#9Oz!(B_wi`lZT;@ld7soOXulStIU29M?~rJ5Ka>2`zD?r? z%O6?je)>MXQR<$*VEw3;Tr?fl29MI;U$w^dI^EH3DYV7G`#C9u98IJ|+(K%vQet2driN z5>8G|u>YEV$^V?Pa+PqorBFe*|eI1#)yMr6DYEj8&$jdmWF!W}KrZlwoQm}g-S1;6mCifo%{)51O5cvNXf&T(t_^#^! literal 0 HcmV?d00001 diff --git a/.gems/cache/buftok-0.2.0.gem b/.gems/cache/buftok-0.2.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..2c3d94b6bae9896e63a04d87d498766b0c51f0cb GIT binary patch literal 8192 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 DZDk@f literal 0 HcmV?d00001 diff --git a/.gems/cache/equalizer-0.0.9.gem b/.gems/cache/equalizer-0.0.9.gem new file mode 100644 index 0000000000000000000000000000000000000000..2072c17e67ceab6baff1875debf67706888e7374 GIT binary patch literal 12288 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 literal 0 HcmV?d00001 diff --git a/.gems/cache/faraday-0.9.0.gem b/.gems/cache/faraday-0.9.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..0b00e52ffc1e2305872ee49d4a8a8dc921bdde49 GIT binary patch literal 57344 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 SvHZsZ|FOV-Eb#x{0{;#4P5wUs literal 0 HcmV?d00001 diff --git a/.gems/cache/http_parser.rb-0.6.0.gem b/.gems/cache/http_parser.rb-0.6.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..3d3d508f71748d4a96108b857f7e4d3d641f1446 GIT binary patch literal 177664 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�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 Ctr^4s literal 0 HcmV?d00001 diff --git a/.gems/cache/memoizable-0.4.2.gem b/.gems/cache/memoizable-0.4.2.gem new file mode 100644 index 0000000000000000000000000000000000000000..41d1f5b284df269b713e32f86683fc7605170f31 GIT binary patch literal 13312 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 literal 0 HcmV?d00001 diff --git a/.gems/cache/multipart-post-2.0.0.gem b/.gems/cache/multipart-post-2.0.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..abfff3d207d73cee8ef1f9dbf0e5ce35747e9b5f GIT binary patch literal 11264 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

!@+0iCWLpYDw7 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 Gz<&d2>B5%) literal 0 HcmV?d00001 diff --git a/.gems/cache/naught-1.0.0.gem b/.gems/cache/naught-1.0.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..f59502d87648e33eb112715bc02f8ef7b0d25f2d GIT binary patch literal 18432 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 literal 0 HcmV?d00001 diff --git a/.gems/cache/simple_oauth-0.2.0.gem b/.gems/cache/simple_oauth-0.2.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..5901361f09abb3e1c4a8b37f7f5c378c1f9ab9b1 GIT binary patch literal 11776 zcmeHtWo#X=mS(77YOrBu<}}c7(r_APW^S07nVFfHnVFdxZr}zQ#=CtxTJ6)UM*C+* zJ6gRXOZM@R?Q=fMsL$BI$$-(xz=6@s1MI&_nEwhVJ3H7v^1t%$a#m&*7OwwQ_iuI< zHa1pfFkv{J*P86bTD9*U_N> z26^dyp?NUT0{F}>Eemd>nzL-9ooLl@42hJg%=2q)$*w|$4+|ncAzes)@ILLDc8|HE zeiM8Ara}_rXQQJ!aj($vf9~D(T}p}Z#Ha z{*jv{I+}2;tc8z4M0Ry8J^3uaUkWl|%^X+z^bIc>_m~ZS;FqUw<;SY(G|(kB&Q=G$ zJuI!v0p`vwT0kCw!GSM3p%&puZ4@V6r8X=;0TVYz^$z*tnM(VY@$d`x5+eb!sNxHd zIL{QQ-03wLq(@p^i(+E6mjUJL92L)4h47Xv-l*D(5lXOMr%11cXX5p~&hITd8z0eZ z*{DmC#Ywl!pLT5KUmpc(O#lAoOZL$5+51ydgG5ZkmA)CsQ?Y}tNV?8Z1^)XrDJ|u< z2&M$a0x6BAvI}*5xKUb#@PFFwt`-*bQWb%si@jtYCUjg&!-}aX8H;rxmlZ zwFtSh8WreZ21fY09D;My?^BvQ`Kss!x4sOnE*z+kXe?%c&SQiaS|QTMM^a+-G`?of zP;f7loIhtRM~>7w4KLVIA_UpWD2Op$FK&{V5F_L?NK#Q_&Uimp8OA>>_Xt3hHN3qh zx#3HlX&g`=0hM27fn3QtZzn)Z@z(kT!3pNOzh!uHf99FS;1lDjGSR}8Q1a>w;%<=7 zDtqk_DD35fg*zngGMC$KYC1)Wf(%^6%8t#d#8{!AGT&+e6y6k>dp zj3WgVzlU;Sd?l;0jTTFQXfvF00WpRQ;U&E|wlDwAG5p(qEUm3v4c(=IP$DD-gG zq~akdRwho&-x?HaYmy~f-rh7psUm_Kg(zDI=3x>mnKx;W!OmG#D28}+4*Y7@-3nDJ zSNLAV&a^saTdXn6>6-s59AEmuwAjsqdU^cT;-hVa8uB?op<0D*d7DR&hA6pGc221h zEFx)kFPQzYcu)jdiYItyRRa{!d^qW0V%IDAXcbz_>P4T_Uy%YIYJv<8t-_Z?D`8bc zP9W)NqFM=Ey#$AK=i%C;XPOI^0|knhma3)&lS_MnuC-#G@K~(%(6vZf4O6aVMRSn;1KcS`Yr+xm=zW}9k;L>Ff`=8AHdCyl z!>f?jJ#6k2t60W*ghOF~uns6m1e-6KOH(yR&QXhXUV11493KpmHwTQL2qC%A*3-L$evNnn87oeQN^r^?4ktgo8QNA%JVwE@yPMtId7MjE&4T2q9Rk+ zl=S#%j-DVtP{bp-TepFI^{g$2oLDZFG&7_0-N=-5w5no_`q{?Dj%^R|qEH;2(@cU2 zV>!5lCh1Qq9=Hn|Bf4z;%-+YhDR%r#yf4cl;P`xtD5Qt8q;�UCjUI%$qWbjQVE5 zAHQUA7)@A%u2MvaFv5~Zh&Gn<8Oj-TtwKZ%e8;sM8eV<2H5mpBeCMC}PHHW0h@5+} z^@5Np3Jk3_*b@deIF|l7Wo;SO!LQN){=A$%ZiU{_$G9w1DlUcjf~oY@lfq1S{3PUq z%&#c-y+$}ClDwpc2D>L;dxl@X21Bc}tL5zDqjKr~GKqJeL7PJ>#v0|aZ11$5-w!<}~t#KUYH7a=`UhX`wnHUEizU7s(!x&W6hG#;3XDpmU6OM+)^; zQ)lYRk3j?aLy)m4+YktE{L<Q-1A^-7dG@O~}(fr1Gs{Y=!LNbQrTlw?%&D@Xv$pggDHktAD9EQ>BBPPWw1JG5R1;w!LOSoLDdHR zlVT)$V&6Mb$j5bL7+l3R7s z@P+((@C%+8VE|k@myD?ld=)*>i7$wY=b`fwK`3r$(N!~XU`RUmo$4SOO{D;rxM!YQ z6bZgnE7EJ#xso4xkTGQ=Dze5FBFAw4qjmmS<&Ou$n$$OmHGL=0Pud!;$6{rtlB!rf z`lTT3UtHn^Mor4^2D3@oY4U5@QZnKnT}(UZ2!G^45n&rFq9$Y7^wtt7);i2Pf$9e+ zoZv*4L%8AMhXpp473k7c-gUc_2L%;I0Mf@ZY5YQ*+~1Vy_+M^pCn_Gk&-IdMW(bNu z>lic5xm*sKb9@?{ijccJjE0UqY(9sMF@?M3tu%?ni`f`fov55|T;QYoG1S_vo!z2- zoy%{FAEwLdiIL9~C8rmKX~tYHs^`^kJZs`+R*oc@KnwiB{U~{Gj^h4db}DBzkW~N9G8vP&%glA%UGO3J=b0i(69g_)(Gl^B@_|eyYP7hfn55WV z?)Yko0AlH=`R*-91lD)Y_$&h+meXLvV&H884mTr92o(#}rdU3-ucM#qYpYy{Cd6Yy zNL3^V)(5ERfZ~lm=T~Eyh`(bezVOWaav6^LJk#vBY&+gN{Akh{YcA4G#!5pTVjLr} zmjlT{L_aQZ@?GHc2A&MdD zE$E|<(%C;7dyN94I~ndkwpxIC zJ%9(f6f-(e<@q>OhrRDpK~>X5Pp)|Y3_(WYPh4|)^otcAlX{ey>Z&58!`Gf z>RVsDc^E;r>>C4oqB$18DpL4&DsLfF!@!Gl@muUq&^q)6TPeMe4bL|T#z@)CT`VaE`S6$ z#e-6q=(QU{K3|k3PUeshIE*+++4ZPmOnHK(K^Ff~rgh|@n2v0sa)=m{T*#@4#i0B0 zM0jF|imdj#Q#wDtkE=HxS)Dy)0t)=`x?BtFz21N8n_*k3E9urz5ylvUgBGQi1a9idK z^=_EtyTuE3RD9o3{Wa(h;)mXkA*y2*^X)%$Kq%a=o_Pj=EHM;6$kBX|X0M^>vKCu$ zmd!2k$`0&^3v=1($8>WoPf#9TpcfmSXH99nKIsso`zqgk!;jphCYKv4&FcrCjH$_o zp0nHtcM5(}kq+Sdph97&#-aDMA~)yp!6*2glhY$I1|Loki=KG>6d3Rv^5_#@Qg5z& zoJ$)Ki|XBH9my5-Knc#my85JaU!l^C@x&Kei*=Uhfk{t1r3e(EFJD<^+zE%&sIz6h z#fXeB9N0`raC_tQcfIuUvuSpr3q4k)^I=fbIP-no`nWvoK-hSYPxl=GAwUQ+Fgp2$ ziMnNh;#UVx1svA3PyX?!W0(VZJswR$9Lg)(Y_J*RNMZydK=g`|Uxr7?kOzxrtN%#C z0X3D4+oSj4Ree#QA+3=8d#AtWxz9Ur>0#+_3qkp!o_K412?rbz+qTz?5dr`Q(xUBj zJ^XYwH;KZ8M;2ir{ji0a2$(eo3r~cC*K6EtZd8Sq=q;mwRcHCVBWe^TN|*$w+Qh!; zKhmYvtWW8i(RHMQ!PmT(n}+c==Y$|+KS~J`y1=4iV@nSLh`_*Q-7Tv;b)9{5C7zZ{ zXQ9$^vr)so$bI*9*l6N-U>8vKMtjjxj^r)t0*8W4hT(Yc+3$O%${Y#_0S<-R0xrk~ z&+7)I8xE#so>Y?ZHr`R*Z+Sn}`-yt@V!56V|7uoA(w;p9G8yS34ctRBkZf0CmhT?^ zbLbL5YWzRPefD7{|2W*uQ}>?WN`~2?@0ZOX!tI&rxkO~FQe21*K?;I$`cWKAvq@F(JZ*+rVEnE-h(^G~>9LKDJ03eX>{Bu$4JlF6P zo&_&1-~ggbB+mg;q<%kdzQlv;q3YWzlqA0zk`GPpdz@6=#OS3y9-X`{v8faLp3~d-zDiKm9dd;Myb z>1+Oq7~_%&;k%cy?7;L}VsJ|JntFV;ML+&dyvdwsWPv9>q(SwpvEOaq8N67JOqzwu zi`NFvcNCs3SkHnkrd<{@7kVOi5PwL1Z8b)e$B!nL*TJ*NHnFwGIyx)z3V#MlE#oCM zA>s9ssyTCgFGA|sJi)t);fXbrFn84)(f0GcLZAL>A>Oa;)lQ_k*1f}=bC;q~gOH)L zc;(%R^|{Bf7F5EW-JhBFCkk9sFV^y_YvK4rQpuK$Ui0^p&zUAJq~-T3CoYVsTRUkd zhHchV1v`lBpv=+$L3b9Ma7NKrK1#0!TO{Q=!f0E+uGCd5aJm-rN}{tMQpbV8HrJy^ zHbWnrbC67%gp3#6N&VI8e)g;iLN}yOEQ2kmE|OPlwPaZU8^w7vahk4q3~6&aX8_Zmm-8 zF4uvRJhP9>*WC_m9b*{>cnWTlJJ4*Vl8ryp&!dQ}cbnN)xOdTBMj}4G&RzVF!RSPh zY1As>tnb|YuH7R9)-U&1#!qk#nfBSI@FD&F3u5oB%S*jar|ox;sCK3f7Bv5zYtzgN z9t8i96vds+y7554PBtzi-}Bg$?{u2Hf49j#5X}18s$SJ5i!k}3TD)C7v>d@E*}x>D zIncpbaW8WBKGyYEX8C3unZ(l)Zr1+DQ3%QIMu!|J!1Bn6ZELU?l44Nn{zPW+OVKa8 zpL!BF4RTA!bDX^4=Qg+`#0@i&)L{gAp8~lnjT9tOp(z4lkLo2@)0)t74zzq7S4HX7f_b_Mt%eKRxu92z?LV zqJi$-d2@zbQPWq=>Sm$#wmOix>p8!~U*?+gyKI%V^ut>9_NrmQq0_)j_G8++M}CUt z{)tLablZU;TDX}T2}R@^dyYerpu%$XDUclJji>)c2+aNo?L)&G&;AZE{2fyxPd|Hw zZYLiOZ^veUYtUyKOfd?3Zaddh9&k5XN9FWxw!X+TUyCPdN%e;^J0PZXpCmIV6w#;u ztH~`1-nS{zfUJu%8E&Hysu83#F`u$i&zj|Dwx4{CA3odc10fRR_qE2?vQ$grd3sL#|1~|8V z`pgV1$CKjQW2RiE@zl9-fG!QxwbrO%Z#>1tZxdaMUwA>3pEQ*>E{0eSZBKw?f5ff% z&GfCKP(v6y@cmFOESZ-@&!N}__L0Gs{Nd8mje%zDXQLO`wI#;7GB7*N<|}~cSX~&) zHIvKHd=7NeNC(sAAI+%*2jJ4Az1@s1%w)&ADm7)^ycrgp8IiXB>z!)^FqkQJDk&RMgM zvKs_`s4Q!h8|UoeZM>w^B-5H6zW>A{I%2HkH#rndU6klgc`w|ZkG8In<}Ei4DOs?P z0=HI`w54cmz>(tB>A(C!R&6VL zh_~`??c%XVGRpQW%3n-Z^ID}bly@%pU8zb3erofwiC>OXXF0fVImor%-|Cwa+SsH% z0xLGJml+$EPfR5%2{)#7hWXRu293|Wb$8%wnlg$FT}E7m+fh7UvC$>D8C$Fsv4d%r zfrgGsSE=U-E8Cr8_b7~=?bV5~*e!e>i8TCZ?O8P$D5A5^OQD5kdID#$!yBgexh7lg z+E(u>YmM2m6F3={B`usSiOOfxQVAuF>9#eAN-Yc9)kG6H<-L5K86h8{pH9=r=3zfP zPu!s|^!0SeE_0>;k*vUma^0b(!NbjwEAa06nOT_hr)i+e-BF3&rg`Z#oj`zv((G&# z!h@GM{VZ?^-bNaUr=?42jD&9a4Yx@l|G1^X^C~*@qiM?}*%<=xg20>hKX<9sY>zblby&PLKIPvCC?o7X2Tqw@Ym);1ODMJf$N7wXm;e{?w zyi;4ek^Z$NNTRL5DTr>DSvXIgQ~a49hk}n0_cXyC{CXN~_DCA|nd|5RV@E0&rK2N8 zvDK0tty>#kX%3#t=6}lW%Xr`zA&^>AbITxEu)5l4f8rf)5QpNJkO~sqGWrdCfe=z1 z;>Ae|Wa&Rcsg3)S0=p-zVPs3!vu{MQINkZcPy7kJ486(4+7GU47qtP@{&KBQ<;yS1 ztbIJy0dZPW3j6%w26E-j>f^`Iy|^Teuzyo98sQzI6U+qQ$p|c?Jb#nzZQ}FcA();# z+Jm!0>vFELaT*c&6~*p9z;h$HyuRB=qJu=M`1k+KT7&hCjgth;Q?No-<-xvf%GZo^ z%Jn@!ldqcXcuoG-BmOZVNs=tvmr~b2w@aWeY~9Tim;S9)?PuTstKf@ZvD%NeN{iFg z03DPq9aqc;lG~k`qv?mM{4OV_h4BlCa2KA>II3|3pYtGOS+mP&LdUy(#puTER2GbV zo0tr_kH(SN90&8r#Ahe{o(rI5M1&ZmcbK3?Rsh3Petyr?Pv1edZ@kkEg)g#3JrRc9 zUGh^10Z)3&ZmtcajRJC%J89k2cW=H& z-xCYP1tz|uTuh}Mi-S}TZLkJcByU6 zMngME^E9)4Q6lR0J^g9>vb}e8#Eitz`cT!)!b6Z_snM=JjwN35_uIA6xzy{oD3`4# z-t^MGhNHYv?D>hmHPPCs0^H{>KP9z?AKhn|+p!})9*t}}+low!*SjKD;xxsU{1rR* zvwOfA<~Xjb_{8-cLfxpNNx9!mo*F(|Du<&pSnify4bNBt(tatq4hvQ$LYF7O-!Qq_ zm>ioAavq1}mily`i>tViO!&{4jy-p=-=u#dycZHGY`K84t+%+WLs@FYUUua_kgkO{ z45Sebja@jQiyyw1md^@KCcH2nKAUQPIJH}a7QKB$~nsJT7Y;<;?5Bpfm64+hFpb?OmZD(~$ zV<96{+P*#OODCgE|0?lyTj=DjSbaLj#uoFICUDwLyqdNkJMOU?lRK@eOU8}i4R%oS zq`Ife^nBAWGj5i?j(Bh~V3*U*(!00y^n8d_ye=b_JT|;;uy^-4F~7er^x`tt8s$1P zb~Jh#vu}M2j=F&K=ZdazhrcN7H>*x}cLO(fAm+9&Po^UEkezcq& z@BjYYyVzT+mvfpiu4PiC7E0E?kcbx^sM+D;w#ZvPk>UNPhFGOM>HE0q_70HSQ<0k? zC2|}%0#vsuL1}Sis65yrERjb}0(KsG?i(=xW7wjPKAAqK8T9vLpaJec~#O8xH`{Q+ReVh`GZBHZqq=rggICG6D7s-B%6nOB{i zuhfmjW**_oO0-Dg63I??+md9JcGZu|atqEtnFAwW3A^p38RKJQX$J|l$9d1A9ByxI zGQ2pan(p@0awC^nx#+c#7H(3p|D#;X^y}^Lttz8hGq4az$HUhtLuLtWx%=Qvg~ZWu zi%v*7^Aza%8sfma#nZumom+bK1f6V9`$HXwEETM!);;|gvrGx-6Io&$aobK+-s3}Dabx}Kx7g&$;_p44zdm#0LBx-~BfFq+Ytz9e-=5Ep zTx_YG-D@y5v)t{+pw@40P~loKTBC}NME3{5YFYe6j8NA+hvG6^*4=C$H&1gCF3Wg< zLB4)uSXbhFc``qMhFo?}_V!M-82~E}+1fLX+xuRKzq|$z2oek<@R$!Q=f5k-;a`6J zhX~l1I2joKg9G&cjQ_*T!p6$_fAD{}xclNE&b^8Q z&O$dTit{7b)h?apzuPg)5EDU=%ms)1e1?$7tL4l>9?ZSgm&+_8%$H6=}hIB80J;_cMQ24`X~ ztGF@Rsj@lKi}5;U-fDllYl@`F@cfDaWs`x zNUScwbvIR5?FfU^fk+rk{LRFaMjVtWIa0wP$xyvLBv zwq#NT1`+8IUcO!anVgfv+TC2r#!z+Dv3~k5gKn>!?Rc|TMtswwtxt=;nQ{*sHX)#x z680-;TZZ9m7fy?@3H#=O)q(pV+y;+recT2VC;=ozEaFTi^ld{tSU8hh&x{c( zbA*Qq_)S&}{dJgF9gjP0^pebW&PqX=P6{M!+fvG^PVfcsBe8vp9*UkLmQfqxt19W^lQ2+n{ literal 0 HcmV?d00001 diff --git a/.gems/cache/thread_safe-0.3.4.gem b/.gems/cache/thread_safe-0.3.4.gem new file mode 100644 index 0000000000000000000000000000000000000000..5bf437650e31b7132f0438f831151eda04ebed1f GIT binary patch literal 117760 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 z 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

  • ehb~067P>YPtqOtur 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

    _l-y=UP< zI3mypZFuFhAzam@5hWNR8lnJdsF#D3o+pivkcAIYlu@aaJ-*& zBY>qTj}CF7JKuxK}c=sn=w|e%51aK?(5;aF49w(UH^MM Shg{t(H($y3XrC>HzFexp@}e>{EM7_oBJY$AxplRQl)-0?Zz09?&^ z6{G{$6_E%v$KN#(eztJ7rA)bdURMB!T$j>>1iD$pUGOxvBu+>|ThPfCO3OSw*QyvU zw!|S~Yv53p%r~hnT!H3KFv@JH0$WKwS7zzi!r77qUTDeef(dH^k~}M*O0 zZiH;SNq6ho7C3F=L3*{C^l`@-XU!E}*L}VPfJd~)Nok^5JFR}S5@&<#;Fq@`em=N& DyN$%> literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/setup_parallel_manager-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/setup_parallel_manager-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..8c54a495dd45982b5d0131b42b32f933c667069d GIT binary patch literal 320 zcmZ|Ku}i~16bA4Pk`}WFEiPS3rn;ESuLu!sAVVCqP8p7uPlAv!^plMpdASNW0y`?(6&Rawd<%k2ill3SrUS&U;_TDwIzWoy&dzC{b)> literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f43f47f2e5001263f056244255441c75e1e00ef4 GIT binary patch literal 255 zcmXBOF;BxV6a?T7$dqQSSeOV4EX4Ec5(KrBp$w=@8LVf=p%#u`WII6rJx(*8boc45 z)}OHbcq0w);?D<@PSmwqd)<^b8l7Xn_M$281qST!oJ$>!$pnD?pCFk&gP>hpu zRukMU+5yA&Gy-IL8jMeCDC!YIitP$Eb#I-?th1`>7rM&+ELUcRpMzpMb_8D2V3Rx< z?5zKavJW)KgvuF7z0Adw=_r+P^vgMKS53KjH2&vlUf0Dj$IH>6o2hH2h%=R1llNie~51e3g0S{CW8R^_rjv6cZCQA-&I zxpQT3eT6Kyjq>bW@=BSvj@8aK%=1!9W@{E2eL!@ql-lkyGS0{(qoe*LGzqChOc|3~ygO#>A4mC214rJbsjJCrPS25VZ1H1&JvW8+c%7*oQ$3*$!kG~MVKlux$ CPL<&R literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..cf37f05d7d9a9ecb6e2f9e98704f4c061c30c6c9 GIT binary patch literal 279 zcmXBPu}j1-6bA4cq?YS?xVY51D2VO+M5yQ;bhsO&P94H)ntH)BFC;1FA^z_sc6!76 z`0;%g=?84y--rXe=<{CqBMsd~UN%Ll#VLVg+cw3`4lNFN4w(Us7Zzaq%}E2q%u}*! zAv1HYBqz9DuszzZ*#HE2o`m)(WVJ!-UAKaDJxV14t7Kn}3ta|3%B6_#qwNFRLRHfw zJv#~xcoW)`Mr;9 YorO*7{{^u;zgj9E$WEwU6*^b_0qJpD6#xJL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/read_body-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Excon/read_body-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5cb55ea2addf9574d1f5786cf81555db7a734222 GIT binary patch literal 335 zcmY+AF;BxV5Jnl0DXrA0Vu2w9fnXt-FG~<@qzt79l_`T|Cr)GG6dkPu;K;uEDBU$+J9M8o?^cu^I@FO_qmu88fV6gC{GdoiG5KpAx&9 zKQJL#1`FMDB};_MDR;}vN3Q{VN#Baj&0vvgW}Gbu!qtD~)mI!0(+x?^3zCPo``vm6 zf$g!Ul#Ima_-Oc%j8kl-qm4h! zr&wAWY^h^h35qrKp!0&3a-r}$j^pAa59jxy`+69+)208y{CKk;v+`nce?ikS^{kk+ F@h<_cZ6g2x literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a6c2819b5f95abf36d33c8029224d6476f75b696 GIT binary patch literal 270 zcmYMuF;BxV5Cz~4$dqPasaV*8gkWhrUzebQMTS-grBep$>^Q{2u_N07_21(*1MBJC z_ukd=2W+!9^k#MKXyhd8y_yg zEny6@aS}#L2lq3%NB=#I0Lh<*6kS4Aj_6}(7O*NiZB(+27DYGvMJhS-MIYlRFZ#v{ zvL!Xp(hWNDUSX^4SKys@1CJ<-;;!S;*_iymg);7!Qrax4eD$R4&-3}a%<3w?{hyp} QOy12K56%y0b_PSBe}s%zRR910 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/cdesc-HTTPClient.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/cdesc-HTTPClient.ri new file mode 100644 index 0000000000000000000000000000000000000000..ef5a4d2a0f1aa6ee8bef983b00c8ad10dc58683b GIT binary patch literal 642 zcma)4!A`?44DA86W!*pm1_w?Qi6iUTy%Y@)J%A95Qw~v@rVx=fRgw<&_aq%tClC^f z6v=+JpP%iW@CA;at|bL{kg6tPE{N9XkcWA^f45jX&IMy~i3=C~*7y=wt1VOQI_Aw*eAl+nnSX%MC%@?exzT(CU85WJXG zYr>gjb$qioV_Mp`bg2qkdI3o$Yi{rxBPDNMHLjGbu_1+ESXP+I##kPW3nt`8lI|wy zC_!HT0uk`z~B0~{EVai~g9fw#rv1L0#{r9*8iS_i} z_q|)LKVb8Iv=ZQXyqs0+ZQE@0s>(BIv>GD;a$;4!W9YHPONzDVqVfPQb^Uhu&D{S* z_k=OX+$4;a7Pd3?jQ(qK0Ld{83Al!=bm(Jf7I0H`+NdgjFj^GdY$%fEDk%CG-3)&6 zg6v5Rw6uecyjR%j@iXww+krI>$RQYQ6c&(OM`r-C}ak?>i PHxGQZen4|D7y|tPFA!J7 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_proxy-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_proxy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ce15ae72a2733de42511d62c33859b06538883ec GIT binary patch literal 294 zcmZ9HF-ycS7=~|mXEuls$lSz@78Y(6(T@4A$pIwmG$d*bS>>3IpWCac49y)uJks z?`SIf7@atY9z91J)BvvRpd;-i>-2aCRCznl$heWzDw^8FlpiRU#(rar+f`j$-k;_? a9Qi6si?06qryCL1OUu3W12bF0LcqUT&0*#M literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_socket-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/configure_socket-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..17b2c0893b6789309511679e8f3d7aa79d0ad939 GIT binary patch literal 295 zcmZXPJ5R$f6h=EBQ<0%dVPOjrf`wR&w@XmLB0~{E>6F3pv$5*fk?jce-{X>jf%Qt~ zJLg_3_pttY^#b6}}U<^mUcr2s4Fv*jnOKb}znJWYq4q5->RtMp7x&i4o6O+HHu@;;~24`ZxZRN3mz dsqgzEU8M2S#ovLLmGW}l_=av2W^07^>=!+iV_*OP literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/ssl_verify_mode-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/HTTPClient/ssl_verify_mode-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9c9d8a0c0df6ce8e3af2ce3c5cd0bd21374b053f GIT binary patch literal 292 zcmZ9Hu};G<5I{R1Q#C`Eh=nak2o@67>k?G3$j}O*bjo1au}v(TTx2_-{5>uikXTRm z?!CKMpCEmI#ungdm=7v+D4Wz=R$1!3Wnan}J+mIAB0yefl|54Kxa4!(mwXJ$0le1r z+uj;Agq#1&j!+88I0+5XkX8EvnY#v{6(+r8!97e8EmV8Q?Z literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/OpenSSL/SSL/cdesc-SSL.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/OpenSSL/SSL/cdesc-SSL.ri new file mode 100644 index 0000000000000000000000000000000000000000..2d44fa87739b6add2a7d6c22cd632a4c387136c2 GIT binary patch literal 425 zcmaix%S*&C5XO6uHtxfV2M^wg;6>b=CzlmLY?}c95cGSpE6{$+H**xZu-><6jY9+jA#Sg$uD_lSy^%x#P zZ~)H^O;iFTIm=hn!ufvWTKJDKD&qXHM-vE4mrnRF@C+u)PHCh-m$p}-en-(N^ET9- zw|yN%qp`MKEv*T$ai|;A_KWgt_X=KAj|7F-3_J>^i+G}U05gmmi1zc<}w!HWzG z3@`6Z-kT%3h4Ys?Cjp*Z=!99jW-yAMYFcKqXRqvL^GJZ)7iD%`h#(sA19002k19lt z!UseTaCpf`kvq89E3QTO7$O+uhfZ0fFkN~Pu;&R(maR4_hkWTejn%snjka%n)dts9 zC~BiB*H+S5jKsdGm2qD=Pj;2^w9F>bh`uL`ymHD@nEIhMT1GsD6CWHZiK^L+GavM) zKs63!HrKXCVWm1y*>nWhY}eLhn8rHt}~9p`M4b5dqk nM%RmWAI~CYG^Vq#D*B4)+=P1ERc4p}1{m=|p8dVUYIOGtTZ(?X literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a58b80f7843cff472d659a195b9e4a20d98d3cba GIT binary patch literal 262 zcmXZWF;BxV5Cz~4$drb$VqtR`U?HBbOAuh;p&d|}GFWHFp%#uE*$$}x9+$8_z5DK6 zEI(lV{t`66lRxcDK8CJc+e<;OG&)CsymCP|93yskDy0s`Y$CwkrF)xGiG59jNqItY6GzqSNi-^}y& MAr9!C9j3&70o<5W!~g&Q literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/cdesc-NetHttp.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/cdesc-NetHttp.ri new file mode 100644 index 0000000000000000000000000000000000000000..4207400abb83c578fdbeb4f53dac1fae24de5fec GIT binary patch literal 763 zcma)4&u`N(6z%~fY1ajb4w!_*A>zb=M&f2)f=Z|5K$%!3A^BiA&dab!;>>;-?7zoO z+JQEZxJ35*^4|C3`AKv|UVQneB_TU)TG4D8VJ%y!C{LC--n(MM>Vw2VMLCyUKq42&@_x_#AalX)vAF! zdDEzJT~BOlN9oDd9U%Ya)VwpL8(fey)2(tP5S8k#Ew7DkIf}9Yu4^uJhmOVa5*qy@ zrSp_7QZ{436(7(-4{hDsc89+= zrRl*EooBHl&f+YTk7M?NLKf!9Li*IbEf%qm9Q8xlDCtoW_eLW~glfDld!udzg1_X+ zu^K%{IJD9wTY6wFMbk|B|0hh}^2|k6tLwo4w|4B!-un7V8gPW%z|8;_{m= z-8qR$cfZk-9!%|C)Z@OD8_y*el?xt6n>OOcMfi6!cK(m(F0`MIG{~SC~7Z4itPd}YNZV}<%7|(QZuE>s0mV8 zO#GN3&q0z6`2_UX6&6{sQFOUXcI* literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/create_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/create_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3faf73009636bb315a1997203ed70eed75012c8f GIT binary patch literal 282 zcmZ9{F;BxV5Cz~4$W#p*6$@KnfC1w9xh8QKBCl)<_r7i!_y!M=d{?{O6-)~9#( z-JLAoVg35#TYv|5*b?u3SFg=!m7lkPkVyynnkcdW@vN%+PGP_f52@ba$P@r}#4pU_ z)xZ8mCZIBk!*A?tsnl=Y&@S2yIoZ;#VumOeTA UyE_G{y_nD2`7oe;v>2oO1%NwUN&o-= literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/net_http_connection-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/net_http_connection-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..374a7dcba07494e3718f02edc2f1baac09ad6f33 GIT binary patch literal 292 zcmZvXu};G<5I{R1Q#Bncgv1sYU?CRcbqN9@GPDDtQwGaUF4V%YE&BrM-{UB-v7YYT zdv~@xz~=4QwE&Oyv_m?&uG#4GI={3?;z;C0>#W6=w6hG@OI7C&l?<|zr^Iy969#}i z(reni{tw!+s)Edq%IMa?)ok0z@Hu*bq#g&fw1lkmGEi(5uqu0Pu+DFcRz*L%iX@y= z#h>9mD7Izqz)LsiREo0G_9KcuxIvIq28HXVc1qWyP-xsY=e$|e`RW$!*WE;yS$b#v U8=nSMdokzjT^OW!GBQT~0|@eAh5!Hn literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/perform_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/perform_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a7643617950430ae3c3e1ae028f19212f25a6dba GIT binary patch literal 290 zcmZ9HF;BxV5QRG+Q;`k~5eo|n3?QK<^K}UVEHbnMDpLl_NiNjFv5kEJ_21(tomijl zzVE%Wr?>p%TJ-`m> zjmX{pf7me2A#r1)RcqmTwrr*U8XZ7XjsqH6LQ*>EDbx$ND0`)`%I>sk@_zQ@Q8sCE zgCq`7v-S6Xe2dz%^W5C<1x#TYHmik%C5Q;zIE?{f` literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/ssl_cert_store-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/ssl_cert_store-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1ba08df6dc8f0f2d2d7c2ec913084f2cf12a28b9 GIT binary patch literal 282 zcmZ9HF;BxV5QRG+Q#IYFSl9vs9Uz{sOAug@p&bxR87$kmPz%S7?2AzUJ+8vU`tEFde%FHI4Jk*R7(68oq1hx literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/ssl_verify_mode-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttp/ssl_verify_mode-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..71bd93b268ee540fbbc4688d50aeb8257a434ab7 GIT binary patch literal 284 zcmZ9HF;BxV5QRISP&JHE7q-9vOXK;v1OXNq+5y3o!E)kDYhlNheF5d)<0?$7Pxs#U z-PQUNiuV`S13ZoM0qN{iTj=YiEMhd`8-pHZVV%MZvRB@eJ1&D%a!&V3dcpv3M0z9g zcmE6fjC08S)EV77xLqg*8NMbDkdTwbk=BscUIvQo3O4ni4L0Sy(OoqxoGQUCm}*24 z=Y-jXF571xz-ni8icl&&o}w6nvw~!2P`E+#ZltsxMTf@yFvi+dQ*IuT;^U=V=joN3 UKk*dse!J)$U9i$T8yO?}1#PKbF#rGn literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/cdesc-NetHttpPersistent.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/cdesc-NetHttpPersistent.ri new file mode 100644 index 0000000000000000000000000000000000000000..4d9087c6a0de4716375f5de8ee3285e820bca847 GIT binary patch literal 681 zcmb7CO>5jR5ZyzO&2AD%(}qApSbQkGB3y}M(lXnR0|Ey$$8~CzpeJ*_622aUvl|!}tC>jX=$uu0KL+G68Uo~nHRS^nLGe8^RbAew0Rc4lZZbR)nw717z?x ielvC5UFCzfQ%7CokL!Prvc$UeynN@vAk32yG14D~>1)CO literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/net_http_connection-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/net_http_connection-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..116e22c3662275083dd7edd20a2c7fbea3e1777b GIT binary patch literal 323 zcmZvXF;BxV5Jo$oP&I2+A+d!87UKEJ5Cm9cXjLJYGFXmtp%#v9*%wg%J&q!Ef%)#~ zz3*cA0qeJCrvM)9X@_)lU9;Agb#Y~p#F5Ag<*Y?T+Sv@U7hV?+Tn5?6Q(`*l2?M|$ z={5ZxFhm^*E#3TwZ!^vz_hW0ca&SF+cQSm99w0@GLn4=uS6&8+%>q_cuMO5kX>?om zv$ag>Nm`x_{%pMuZMMzcfmLqMDIaC0?PnByaDyP(8WgUd22F`kv}oK9W2{-!#p)LA c_uWKSdD^)7vnZXo+RV*+7Y1pbjEs@}0{vWWw*UYD literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/perform_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/NetHttpPersistent/perform_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d0a991f5e2a19f1b2066a69a2310ea384b24248e GIT binary patch literal 321 zcmZXQF;BxV5QRISP?4oW)P)6w1*D2(MAsz-k543t3fSU34?%{}k=G2Zvw5qf|< z(i4$;MjuolG<5mbx=rdDQa1{%It%ABZ^!+|=l~*o9HMIpY2~=5&@SMtl1gKf7g~uz z&cq^OCtzWa*dYR0#QYL(yhygmE0mQTR8*1o%De|Ay&V{Fp^;h1I%}qSfeF<1yDZCg l(d4VEDQk0q=IeUOsM5G{{cls0>TW$Z-^aIbeXn^4xs&P!0CB0~{^cJg33i31i+Y}pR9{~o8Ms3Wp; z(&_HqclUgP*Kqavplg6D_``-taBJeZ!3x zHpqm3^4`1%>!kCd_W(ySf)=@k>pfw~?dM*9Br)2>-!m?g?_7Pyr{LyZ0g$PKC7;O*jLFfatK0h7i(Ji1sO6Xd8(80*Il8DKcCdu9Q?JGG6 zWGfVbg!JC~z5id*S@sN9k6%p<@L*gk^vX27mi&{-7+I`^6Ix5He2V~mTQWkH@u(4h z0lqZC2I&A!lPFr|2CnzOm2f|M3lQmjE4z@vw6MYj&yk_yjAn6#n}2f?Z0m&Gp%iB1 z`?{~RssTUkl*jEL4!05PvFPwY0~Q|p-df{=>b5xc7*t~?fA!J_e~T!3f=RJaS~7C2 zRdu)7+qjEfl8akc4LNyXS{2Hj6ip=ga^p-}22p8QnoU`oE<_)`tfV%-b2`cCH0Ov< z7`Z(3_vNvB;xU3=2JX}jHsS?-(4CLs81peBlUfV!Qzg&%n9kBU%&jv))8~L3Fh|DH>37)$OEHu_{KE#YIZKdMEbtF-Xr7kIv&f;^_JKl=sQ`p8)V9 g3Q(rwnHuGXM;smRp;$0-@&Erw;QI3PhutS{Z)%{zng9R* literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/inherited-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/inherited-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e08ced64f938a611247ef6a58d05a77dfa6e6557 GIT binary patch literal 277 zcmYk0ze~h07=~|^#dKLjCu+3IhY{ z)jRjxceVP2_4_jp08i7o)9Hk&Uz=rHZ({ZyLyFvsAgtB)K!Cikwti$KP~uz=C4ABW z;O+OsM0fiSw?O;M%TFW|Zvjn!?vwMOp7S+^_B zi|rvuvL_!v8+0b|lNQQM$H>Qkjwd0l<~Z^Jr&LNKm)hbtrL0f;S literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/supports_parallel-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Parallelism/supports_parallel-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3570933bb6beb96ff47b7af287e05f1d66becdaa GIT binary patch literal 292 zcmaLRF-rt75Cvch35zFarNwoz_qMQ_YgW*O6el7l7FUF1H><(PPDmz*|K8}@36=wI z-uI51XE=MhqXFQSIUUY@qvS;{F;e2Jqe%wQp#X8eSMsK>_h>$Acr=k+0(ksQ_#CeO zzHLRXq<9fqv4>SG7X3i5Uc8-2?ySR$zB^S?{yV>x_QU0}?SWD-xTCS4 GYrg^8Odz@62SkOr) zonGI2zUNNx9xiwHwgGswz889H+d)fyu5d{fJNYrl5D}n+zqu>P118XbKXYTMA=T|!g=*6 zq8y8oER_jSm_{C3*?bh(V#>>uGmiGh6*l7sz9YbM@>AAutTJj@jv3||JEd$!IVuU! ks$O*mI;(_egtKxJn_FLxlS*>^AH5_O&BfmvY{u1o0cZn$3IG5A literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..dd2256f45671ebb3ff430c7472609c4fd4b80c54 GIT binary patch literal 258 zcmXBOF;BxV5Cz~4D3oTcSlG-03-Nqif&fbyiV!MO2J7rN)WY#uwgc+F$8E-w-hJ;~ zt-oOV`AQn#*`M|%A8F{f_PS#?8l9`4dJ`RE0wWH1Dxm>GHWA#SGeu}EvRR`cLO*YG; z!NL0PB*#dT%&44^G)hfA7duI19Q|?5`&Gv_561sKp1<4r(6M@%T5h3lmu>G9Cv-0k GQ{w-5VpB)} literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/cdesc-Patron.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/cdesc-Patron.ri new file mode 100644 index 0000000000000000000000000000000000000000..b75ddbf55748a207412ed64ac479ef89a44713b5 GIT binary patch literal 516 zcma)3Jx{|h5bb~*w`sdnFo0O{18C;+5>%*^feHbgJVcJ;fQ4g6woBpPW2fx`LPDN= z@9urvo#8E9Jlz=%uran{YNeQSbRlt>rH{;8qYPWtLiutw@vSGCr3m1ngQm1!$(v=17ts)aK9oQ!ia$?0f#2~Emu!ehwD zL@`Yu?RT}3oT7+fE%p)lkB=}r@2&BId(i~?1g5=}AIyvRDYKc>&NI!$Ns6R&Ffis! zsZd-Om$7fbtq4Pv6VA!7@FPH`k%r6$<7j)@{Yh>L1M%KPbEHJ$R+~3V~*r+ z|HXGqN~prDo$U#37GjU_dkz4_n5ls1ljgb>}Ty O6nmpMp?h|ilK2JBKw5YJ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Patron/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..18a486b155f8202417a11fd669306244fe4b560b GIT binary patch literal 265 zcmXBPF>Avx5QgCl!8P?(LYFMXLusMZnlFn(+kl6ZQryXdILUG&BI|@C6Y}pX*ZaqF z@2&G6*nGc}1lZf_QN?9f8t zCSkNB*e==;{dsZ#iJnGfV-7{_(8tiN;IA*}^?q7cOBDpQFnnoS@ zNnx+;Z{UNckw+9paT>TJ8N@R~y%j>!ao1M17ue`LpmfMT4K zvzp*x!S)y~(+H5|X)r#mp{Pd;DYh%v)V*~ktIn#bU*szDGhBu2z6Qm1>yK2hKv++MKbGt5%`H6XEzJ$JCc70J8(7ij1 Gk^ccH2T*AM literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/cdesc-Rack.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/cdesc-Rack.ri new file mode 100644 index 0000000000000000000000000000000000000000..d9925817d5378cacffa15ec21decb8cb9af9e7a0 GIT binary patch literal 1048 zcmah|QBT`25bnd2riHRG*j|{XQ(iixu8nxugQHF9pomB?At-x^P~;{KwQyq3acR-m zf8V)Hg$A3}hp4{uec#>ponN?D-&rU_YQ0|%3Do+cd(OR~4ZJ)`<|rU*fjS;0!R{T5Jnxc~Sp}N?n6b)KU?fnm4FFZDk96Z_5MKo?Z%=v28Zv0rFrCqY z7D}+nR)pKnTKvxRgc@Enk#!5_O05`hc5j)6O0{hnh5<5`LrR7Cz{{&E`0t1UBeb;Fg1nf{^~*OO_>l9=2DByyS}a=HUMzW`p|m(>(rsO z3;mMKA(QZs%CdZ@lluVn*hibJK|nNi-Fxib7S&f>gtoJg%`msF8=thpoC_9tAoygE zugo6QPy>t9*OO(5AIgH8WXfp9%bP06wJZ`tCxRt1Pp|_!ca=<-kaIui_`#MRH)7|C z?5r$CWhz5U6Tjq*$lJX_ieY$xEXovrTexZcH<`5P_v2PY3$gX zi(1;u|MkMkEv2PlsbQIgCYwt0J8GCcL|%t4Nl{?1ltxTc#Yqs%Jri|mF>czVo1zo8N0l(7OGLZ;)L*zw;T3;1EV7_HUIzs literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/execute_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/execute_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f7e77cefc42532f7923a4f4486e953db0938b9f5 GIT binary patch literal 284 zcmZ9HF;BxV5QRG+Q^*>zuvB3Ifr#hp5(HSvP=*So4A#ZDP^*p|YzOGS$5A%6JL&2B z-aA`=K)!!*3gF3}b`%e;YjS;F7dicsnj%S0UlWDMfW3;kxEJWL!&Az4I7adSdsN4p z|LH9g07sU?!aT)=VZyLzPHDuL@K89ummsPI~)y2l>w(J*4nM|{z^hxpP zTefBIz$-WCC=Z04wx2=v-VHKhYe>3YDraLN2icNwKb-SsmA2fH{eIZY6q&BOnNwwH W&Bfe3eL`I=4d0v}&^#Lqf&T$4G+mAW literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Rack/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..41b548a4ab28e128190832d2016e17e7535033c3 GIT binary patch literal 269 zcmXZXF>Avx5QgCl#c|^`bV-NcDS;AezAP?n10K>LxRVEQlI2E3mV_h|^6x9*ZZ~{9 zy!VvQ|4OSGswQ$rre&;VULfv>Cpz^04~UH0BLf}PAwF6 zVoGuYo7p;}yG<4#!qX^p$f2k$y5PG7tm;835mhBwHOz7q`2<%kx(COi+5)M~COV>VmbrD~APT{GUzs#lI M#*L^x6nano02w(}{{R30 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/cdesc-Stub.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/cdesc-Stub.ri new file mode 100644 index 0000000000000000000000000000000000000000..ab9968b945bdec3838e60e0a46b3f8b0d4b33946 GIT binary patch literal 598 zcmah{Jx{|h5bc1R^aBQv80bb~OEvJ(}i(Qt`fPJlcv(&&7_4KMfx;I7~;N(1mJ zEdum8l(>|eC7Mp)btBgo&~jW|&73j3w(hc$ypYD^Lko!h-%!WR2vePT8If~V-3onwhzM^+X z`@?m-75P`{5OwA!=qu^Occh2?gyd~6`MuZS%dgQHtg$0EL7UKCj5ClZZ&<;?h4A$9kh=m;o`z+Ldk3%-blkR=r zduQtp*u1?s3Gg(Y_KF7AwHtlj6jy`7PWiwsk{lj0$X@HFU^RN|@RZ&=oJe_qqY4D@ zPEp+ci|n$xhJ1>`XzAd3(d^NG#R(ueqg5lVA+IL%6xtPBR=qZ=DQ=7wWxtrpq?<)0 zCC`Hw*)BT*tDM!uXP+KF1Mj`FoKP6WUC*T(DUkyg%D5lKSi5S9?VVTOF){v9Y1sWt Ys`51IVlJPqT5gw)2j?xCXM-WIU+HgOzW@LL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/matches%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stub/matches%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d445d9f14f1e4ba78efa26e4de34ad2961993c32 GIT binary patch literal 305 zcmYL^F;BxV5QRISP>9$n7M3b3fDj4mbsz|cl%WhzrVQ3OxeyB{4)$57|GthQV0@>i z@4I)j{D9Tlv#9|dhy9kgGflNp$7OQXBi9|dhX|sVqD*cIwAkQ26dN3wEWnN&1H7}B zmw)9=R1^@8UTRevxR}vfv|oM%2p-?lz)Ohp5iPrF0jGJZG?mF(E19;lBMqWSk#aEH zSs87j9b~!b6^o9rQNyPbtu?)1l$wNTMQsKSWG5tP^OI#+wJ4MOD@)%#Fod`2cKsVB i1X=fgkfzyRPm(+iOHZanAr^1X9&xK9(S$Qid`>m@-(lbD>rpUt~L~^6#;g<)(Mv zy}L<&VfXz(65!1&C-i6PyPeuLMQZSxK=Ro(#nX{n-t#47dOmry04+KX@Z)Cz5QDGD zv4w1!g;tW_VHHo@UgilP@bieqr;ybXx88LdxT^=Hu_8F{bFpJRiik$EmOG8&j9?KKX*Yd7Y+DX%6Ggp1q>RKpVi^2VC7VtLt#Q@-xRggO8mbVPtp zO!EGJVn-N*VoK5)<>7XL>_zxa6F?>=r$<~vQRf)Ob_JJpZ>(<0J8NXsFQ6*ZW=@3} z^B5%Akps}$JA-`CqBG-HZAy|m#>kNq-JT?8OOW zNxfrzw%EGiJL)b_uNjTEnmXOkz)6nUSWmxF%6e7h>&K`0wan7??YuEvs<~N4eNgDp Jzj};O{sD6vQM3R6 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/NotFound/cdesc-NotFound.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/NotFound/cdesc-NotFound.ri new file mode 100644 index 0000000000000000000000000000000000000000..5a571d2bac5d8ee3b1df47555095a42c59a38c28 GIT binary patch literal 453 zcmaKpIcvl)5QSX?S=p;dAWfR!I%Hjs8i&mqTx5$qDiubS&p z06RZ6E()C62@2geJI{K-tXNxXEFx%c;QmBKQHf%j!gLrLt$3)Xuo$fIl6xtR>1?p-lX)4FupHI9V35np wS2B$SGCRh3hzUi9i{n)s<2$Y@=qb}vtdjiV^*j_R7FCx0yW_wr`QLN>0%kgiKmY&$ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/cdesc-Stubs.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/cdesc-Stubs.ri new file mode 100644 index 0000000000000000000000000000000000000000..fbd7f636c917b4b96e200b0da3b3ba74f4ed21dc GIT binary patch literal 683 zcmah{O>fjN5Zy!Nc$3|7Kth6EP<}u+=gEPf!b&*+60|2DBFCAu1}C;`r)B>=c6OIt z)Jn*w`Fd~O8(+{nc=P>}764zh9k{wt+&T7I(mGFn_^EXS$meaH=UZ-h$9Di9J8nE$ zfLnAPVBb`d(35>@f1>cDB)1x__NZUD{WTeYKrszCdJ0)(xb=<^T_&`oYyoN2ONDj* zUdeXT?|C+XEYfUzV7az!1cjo~gY?Y<@=lKTuIa5F8qZsWjqV$vM;{nm)1uN(MY$}> zv|x+*B`gVoL=+d17-b1$W@?objKmrp@hMjRzeSk5G*fM~c!T8;WQ-a=Obnj4JMxCcH9k>?{r+B4}mwJqP4g;zA zw_|CvJHw-9I*Z;uqLuxwapA}kS+g;bYye)aO7iooLer~CticEbh$ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/delete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/delete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5e770a413e06645f77179f4d45954b3161ee8ab6 GIT binary patch literal 287 zcmXYsK}*9x5QTe?Sek3`;w4593&rF-MTn?@9NL4{Qx3~)GBHax*|0l7ium8%7>@&Q zzVE$@)Svgnt*Ohkx-8MTl$=FfPO9-<8ExU37tE^F)ia63rCe5r!yk{~b>;(^2 z2D{)0X=Xabq9v?V|LH_yO(z(oCSe*;nVvn_2}#;~rD<9&iumS!KyJ6u^h4G~kJ0zf hHoBAARHw}Z%|btH^*6wud381SJs8`ee%9z*`U~znT>St5 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/empty%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/empty%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..73b2e76a8159ebe8a46160a4aef0cef7b888639a GIT binary patch literal 261 zcmXYrF;BxV6ofkAm>uqZ4x=MkZz7J66@x}JInlQ!LkO`DQTkwyIPruP2k zdv7k{FW7v%+8W?_IPVp8wy8GyvP|Qnq6nh5qD;31I&AP9G7XNT9Kb<&0{Em!`rA49 z7!?I1<0Or)EnF|+9^Gjg0RlhuYM>aBd_+gSTERMRwNYitjFwru_*p2K`HX`8;ABt_ zz;oMc5}m?E4@WOrXL~^?jS{vMwH+wPUPxu^H|M-smFdmhh}7-ae50IaPweM+$F|bg c`gA{|c@n-_|F55y*H_Elck6mIF9yBme_LBxkpKVy literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/head-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/head-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c290890f32e9f2093d9e28ef157429de60ccf64b GIT binary patch literal 283 zcmXAk&r8HG5QX<3aot`QFJ5W|f52jUo<*prg&x*}uBRTtBu#DDv?<9HS;YU{bbB0l z@B7}IEx%y>@oFW&bAQ|^YHeMu^?8|Gvp;bDU2QFv>0njg+WUe0^pt?SUd81z2-2M~E%Hvj+t literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/match-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/match-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9914055e9f8ca8a516aca0fa24fd52f2b33deb7e GIT binary patch literal 294 zcmXAkF>iw~5JodpB!V@{(go2atx#dUEL3fg7}6n4CkE>brdYKxwGUPN`#gT*sxC%!ApEPmzuue}w zSwb{UT*=13{YpKf{h3Apub8wLXa`X-q9s>vAS^nmM3ux!@~m48nb$0Wj6DC@^57I) zAuo)U#Cn0P9KIdvtkH~+E5S_18Z(e5JH~}Fe|etQn<{xaTJbx12Gh5wG#-)qG+r3O gx-{mdogWu^5&6LI7UIvcIjoO=7^_jeDs(RY2f@x@bpQYW literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/matches%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/matches%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..82de4bb4fd022ae842ef285a56cd22849b82f093 GIT binary patch literal 294 zcmX|+F;9d*5QVQWc)5#K7aJSIMk5jGxk8LeLU9&)Rur3Ab`Ww4OLm7C{=JJNmXo~s zzW2`7U$FalH5I^fKOKl0qsm=-UPKoia@CM~3LtpPi|8RoiwY+nR5&nMfFn5u_~cQ# z+yC@F$aA~ zEss_P```#^X1bO|L#W#R+lktmPB2PM!qlQNJ$teflC=3r)3jU_(aoJ>tWI$_AUAP1 jzmj!vD2o$KY{Fzr*OW${6JJc^4olAcK>^@){ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..50e5a42b5a5be706699a9c940ff0dbf2208ab829 GIT binary patch literal 266 zcmXBOF;BxV5Cz~4C=Jb8v9KU7z(O)#mmnaLhcZBzGFa!tX)PQ(vM;Lo@3F~t!@KXj zoBRj%U+=C5c(vD~qO%*iz20(`TXo4G`)E0PY|!I?*O(b_CglNI6$s#)78w9i@{lzx z6!RjD?j78(YWp)^XkQS{DIl!K7UxJy-Wb{mu#(`UEgZ2R<_&bnwg+x^c?OZ&TZ N->35vnm24%{w(L@;rAwE=Ac`bCf3jdyf`{!;+sVT)qn{}|IyUpkBGG?uT%qF& zFVDksw)}+6`-?6Bp1N^|RO>R|H0POr(czI>8l(r_Ynu5FsW74xqdS(OCo}+iv;^?s zKKADS9eZgCm%Y)11!1Y-ddBaBISf63a}6zaw1joi3qv+vz$&R4g_+M(Bg1O;gibbT zLUNWzBfZ$$LzL*YAzq^>o9@f<%IKDpkP5l3c%eITWXmNgeTa<8a(5>aeNS`m{{X(2~Z%M-aUfWqMZ#CmL}Kxkgx04q&f50ld>F z{ndYX8x;k_c9cff2p2PXC){DQ06{bMYM>>=xfPClwSZOLYNN_DFQe+ei z_fAIJXb&vMUK8(>X!P*udF!y}B&1OsTVCTpf$X_d2EQ0%)uK!*qhlT1I#`Q#z_ j{@Eng(qMhKouGLfmaYC4gtMs6=f1D#dSRZ7@SgnwD)(M7 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/patch-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/patch-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..49386e54f160f9d5e3436dde2240830263e9b996 GIT binary patch literal 295 zcmXAk!E1vs6vlfPuIRPwvP*CtscvHyK>9v^(~ z_xrw^^#wK`Z$<#T^wUvdYwBvFZp%0v7>YK4;Jqm0ZNV(7+2m6-8&Fz+vvdgXi6eIp zOLQL;1w_NhwGsyI7wVDO>o@>-#n{On*AV3cv*@Z7gn6U1EMuY-Pn*S%dd)0I(ernf z2m9a*S#COow3Vz@{g0 zo|Bs(&mkN}X>^5fGc$L>9>xK{3&u|Mw1hAlge6xlV3jr6s3KxU%cPkFiMLGrggpM) z%3u@hACL}LN5&w5nyMOQZ zz3(Fagx&j#ZULUA`6zJEU9*#ybs8Iw5k#+5o$f1US;yv(>6k%b0Zzgpzz2HnZkFI< zR8^1|&y{R7T(9Dh*|RqQf%l`BFovWw%%W>Huq}J3M4b{PdET#n9!eHI$Dlu09@G;Q zr5+{HL9k9vUyk-xj}#eKg6f{Odcq((%7xP3MNu@HI=#O&42O(x-OYzds*Ehx!a8yw jKff8-bEVt!-NKhi*th-Pv219s*3aLx9hrJo%(>zZNN!$7 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/verify_stubbed_calls-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/Stubs/verify_stubbed_calls-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..891c71f3f5f622fd04b7305949601c529794f5b1 GIT binary patch literal 390 zcmZvYK}*9x5QRO+wzlA@2%?82Ui8xDCQL68YaoY;)OyNcnN23m;wBq*H& zC3c=Hz?Pf`_zYtA@UL^p(iEm$FSRNR+?_MmXutaoAQb2uYW*0dNr%?EoEfmS^xk5 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d7cc10ee51b235108f33f8c6f9525c99ad01be47 GIT binary patch literal 252 zcmXBPF;BxV5Cz~4$dqQSSXfY4U?HBbOAufwLm5yyWw6eULoF_LWILe#dmJ*J^xmg; zSKAZpKi|9tcyX7bNoU`8dwboKHyVi;uy@gv_W}dz*Wlbb5QKSTHv)GZIWk$ zy>(wv4#AHyp&}#wAhmZX%TX#r{+Dy!ZJKiTXxz`!(yog(Ke5crm(aKCt`8qZq*uZi F`5#a~P{sfN literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/cdesc-Test.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/cdesc-Test.ri new file mode 100644 index 0000000000000000000000000000000000000000..f201ce0309acfe28678afb28a4ff0464335c3d2b GIT binary patch literal 912 zcmah|U2oGc6zu~_(snB#1TUMw3W5qWwGoewHU$QiA^}2Ug9i&mPU5ttt{vG9Wn%ny zu9Ft_p@~F_a_>Dp_v`phaE2e9yj2CpAC+EFaV)4YF&I9e+$ z%JH`iV2BWt<;Li5fALOIxq;hA#r;i}0R+1~u8rf3pmO=1OV-I^A&+5I?>P?BESR0nV2^BR(G0T3JvAE8QWyQ)~W%TIP&2+~v|(Dhqarq9yJZ zR0wd+97h_CpqGlz8|{FtFTUp(;`{LJ5$|lPZIGd5KP|?eJ28@g_h6x|s(afBBPfdPBGTxlkskhY zdnN=FQ&P@$9_|+G0mDz40CGnf^hg^h>InnIb_LtoSf?9)@2o1#f-iH&OfMbjLIG?twhOeKV=dmvG7uU0M S-b8o1_7%q*l8gE+Ui;qHx&EuLu?Opu;&xojQa!ZR&+f^M)klxNmPl_lF<< z=PLh&?awC-0Pp5msy&SL(y1t!S@@uZ6>8983j8Q> zROZj~$|8|?75Jd&Wy2s(^d~pXzi}_VG;h#D7`Bmg{I;3oWQ1tUv5%) RiXQIP)NgV#>JN?HvwwdMR}%mL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/stubs-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Test/stubs-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9989230ca21d9721e47410bb920e0e7d90711022 GIT binary patch literal 259 zcmZwBv2MaJ6ougq$V35&PApkkcW*LZmQ-ycd4K_>>cC)KCl0mh#F2d?#M|SNwfoWc zpGEQoo8yOT0N#lF>Cq&Dr-3FF7_iS;@aGCWws?($7Dv(^pw@w2=FN^(f-jHXY{zO? zjgzvbagfd89{uk$0z`i5^*{-%$`L(<(*vYsXRH?d$r_b+b0UwOzd}wi@aokaElSrL yl0O<-Gn|9$yz3>QvRb-MHg2FO2dT7mm!c}yf@l9fj#|}h=Vu4!d$jKsLnv-8N>qCQ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2c9d2c3c6c68a6ba38c860368a8e57b96d7aaa48 GIT binary patch literal 264 zcmXxeF;BxV5Cz~4$dpEG6$@KnfQ5LzED~9< z+4ddwZ_iEwJlf@`(&+kbug{zELZUGQ$O~)ATZRF9Tym&KpHu*77e6{R$D7~SfiMPz zpM}xV!SxCrF?`M*AnWs_Y}!ImdkiUd8`#x@HY&?Ti)vW)Dp#EFD*f3HL68G!f!1!) ziH{0mj}d|~ox-S_Ik KgyzX$jPwW7yjB$e literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/cdesc-Typhoeus.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/cdesc-Typhoeus.ri new file mode 100644 index 0000000000000000000000000000000000000000..efef68b3a9645e612ca6ce32898cdbd01bd84b96 GIT binary patch literal 733 zcma)4J#X7E6!cI?itV^S>ttw#0!HUr^V3ij`2ak$Lz_$-2#R`gh)^O+Qf>V2`{>w} z&>%pdiSJH#@8jNNcX0mW%1D6k#bR^mb?O4fZ~P0=alzp*DZ=;v_Go zIh*Xil%<>1RK`)G63bW$Guu~MNtQ(H!ei(yr}l)_sCg?ou|*f>d0lfPxUkLylmTn< zOkr-F`Yi&+2klmMK8Q}@(Z86nw-GpzHg=o(4|clfJEKV~~xI5x; literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/configure_proxy-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/configure_proxy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8277172c1af601fc6557ccdd49f2b5f09eaec9b6 GIT binary patch literal 291 zcmZ9{Jxjzu5C-5YBpwE_2{twoEfmCTJ=a9kK#H@Fvr4gSlG)4RCbRB`nt$&e(Z+U| zd7pQV)^Cu#K2ZnoFwI-^1NBX&j_W+@Xp(9lEOKM%drlyEuIjv~gcZG*<9;uUM+>l< z%|IC3)&Gl4QdN+e&}!8YTrA91*!N%nq8Ub<{2J2I2Y$)D^Sh;@20EOBoKuI8w6E7-n#BB2`rluU>frkL z^8I|@(eeXU?=PkWc+%4b!(h5*C6DXkyfwO)yXcU4uQJG9XAl~(ljR4j-e0H%cp9cH`kuOGrB3T?-O?b{K3HU48KmG7NM5Ttd#t$S9iL*NCJ)Rx=NFakt37##c((sJb1yJi7rrBoX0>_#h*%bCif zcaU;_gdVI&Hpvc(l8o}KN8YJn@0he?nCC(xBgx_#AKM)hsOhIDie^z~7q=F_?yqq8 czB^QuX?*GY?}2!!+Vwp0jjZANS##%#UqlaL(f|Me literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/parallel%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/parallel%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..038f9b7006840cb4dbc04010d03feb7a45b73f4e GIT binary patch literal 274 zcmYL^F;BxV6ofk^ZTebtrzsFTTtf#yC z?#|Zluzh>BEx@Ch4;TmA)mwdD<(E!*MTGRgfW3$+--#r2YEI5hxriR%IJ?2(6mI^# zdnN>AZfZ!k7Ot1-gYut~14x`{L=)GLl_?TKy@E~IYr-nOCEXPLf+!N_L@44f;NCZE z&yK)LJL)J0RGl^-LH6E`GOC79+FrKS#MB;SgJi!s=k=<}H+N{hcBgcir56`}o0B5i Pt7YG-^`oLEQX%jk$HrOl literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/perform_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/perform_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ae6088306642bbe4dc5e759e4b6532aa7e37b06b GIT binary patch literal 286 zcmZ9{Jx{|h5C-55$W)EkA{Ms501NSaU4no}8Ongll)*?Nm z?mgSSLHYV*2Y?5&957CH>`QgtRi#5Ot)H34&x9coAkS@A)h+jY-ci`VH(FsWf)gjaH(TD^zFgY^L$ud|d$7NR`Tui68Ousn=;B#Cr20MdAs+hK>BnX%PnP;D}*G#n}IW0*Z-W0pd z4g%wpLTv+MeOBKM`#_6#CyX^DAqC9SrjsHMuVu%hW)h9O?ZGp$Kbm)%f5UN#eP?Ow z3;IKbHX3_s8JB`$Ln|DtcQlj>iJx&Cmq&RxzZJvB`mmiY{V&dboBK&tolgy(Q1?te INM=m@1(s}aSO5S3 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b9b30e9c8208a72ac99c902a11ba5b2099e427bb GIT binary patch literal 270 zcmXw!Jx{|h6h%8AQ#G(vENlS@ScvD>B?z#Tp$w=@87w<_Ar_8p`~k|p$5rV1bniL$ zovlA$`~G4(fG0EWF^;xxx9YqpFFbxH43PkNWled_!!z1Z0bR2Y|2}$WHl^;DqD{HD*odiy(Bww z09xBgMLweFmH7;O@OI)+NR8YMyt5`|df*bZ{iT$)tESxCqxpF_w(BDQaCussFRZ&- O_Ptp@3H_`^2=ou1+gRrS literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/request_options-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/request_options-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fce6542947c22ab45d136fda68cfadeaf4fb16c3 GIT binary patch literal 286 zcmZ9{Jx|0i3TnF`m^wsh>(Yoc4*3A}-;+~eVYU4F zd40BhgW~mxdVmMB9575Yw1qlv%EIAiL>~m%pvd?PvS;3u6_-v9a!LDxv;iH!aj_F& z^w<9r`;2qQZS1t_39eS=Al*l_0LhFqny`huw$cUPZeUlBN@G*rXw_BY3ROuvIaT;& z?p>Gdvm>yYW);MQa!}^oi_y_6g6uR38bwbgr0ZUEsOg(A)^3_|cZ=rh?v$?c^vlIx T^EBc8<=XFs+${B@mfo`;!0=zq literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/setup_parallel_manager-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/Typhoeus/setup_parallel_manager-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c65a2bc80633fbc9b90ce87ae4426647a458a277 GIT binary patch literal 310 zcmZ{fF-yci5QVRhcz9TO*j#f23vEm~VGbdp22$J=5~~!;B$-?mH#^Jj1_|PScaLak z``~-uduPjcSiik+1MsA$J^7y7YAw%;c;m>AMi{iH6e%&F#v|DXqSw5LAM%j5I0dXl zSnCtu=!b@#T8c2Nmw#)I^tCv2rYI?-7kgvVNu;7&BGeQ0;0CdHp=npTSq$ww^?$%Mzh<&Fsf#V{&oHNkpf z4j8`10U(=WZ+u!nQ4JVUY-X^mI_pebuANoeZZfwSzLL*Du^l@Buc)_4o(;Cve@58_ z>SaRZjHFI#@+qTHD&y#fbKcDAa=9`7`|0{!6}k5AKQa%5zMrbzDfH-G9LC6h0huXH A&Hw-a literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/cdesc-Adapter.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/cdesc-Adapter.ri new file mode 100644 index 0000000000000000000000000000000000000000..405ba772222290e6f1f53ce2c7dda78e1270cf48 GIT binary patch literal 1504 zcmb7ETTk0C812K9b}g5w72BkuDP-&-q|s`VkmkG?u`)7^4zco-hsaG_YT?A0?EwAv z`bi3VW;-cq{t}$u*S@az=-Nw{b`$ zNyq}BoAzuEFzp(D`d zGWG-_oJ*3=9r)Y~ydNjUl(QJQlQ~l^{D?axin_5$(wzzE63*Q^FBg(C>8f4Vtuq9I zq^?OT@IFhba*-)E<+P;E3O-|;v+NvXZ!{$RQ&6RM4F|O`0BGR#IhzhG2s7vAvOf%n!TI-qGZ*E+Ao{mv5O z<0A~U$l|#a*}_iy`Y+l5#sYn$JW5GM&Z)HPY*}@#p+r0Wy$x@wi#day*h$+qQbwV{ zkG5s-6eY@GA(%2lum|*P?3`%mr=8&12$IAX{{h!##i|9mH)Cu4dXdisEtH+Ixs*_$ z1s5c_h5GFw#0VRqbB21A-44J8nq)d$XN|z?9sC+kM&n8Jb2R=wIfAVQSHHV&c7z_n zhIiHzcOeSy;%5BtoS5iMaott>sc^8f%)Ak1M%kmqb(Z5O}Ms zOgJttjG_9gmEiLj7Prdy36mO$t|FH-s&9bNImD-+vt|PL>*ha%llQ`0AY%olQj_Mb zVXOL14XC$YH~ENiSg(7yJ?KN=Jv9_FiTX&wBs9I&2>piAnaIKxYussSIk_%$bpyY~ kef$P*;cff@@8C~(h`-=HxY6~TOhNIhyNCQ(Bn78`0q)bjssI20 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/save_response-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/save_response-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2a381b840a84895a72a09c5440c51e87cb885b10 GIT binary patch literal 313 zcmY+9F;BxV5QRISP!T3nSh_^%07wzd>l4+CJ(zKi{yHN$$e*Kw2R(Y zUQnmJI3P62d^pis>VyZWQBW&tGCoM1kf`Y^&&%}kuk_CgS~pp$MVVgTpgCrV^WX=U oC6bykOD1h#lKaFceLJB=9G0H{4h#ogU(G{a$abI~H8_`l16VR=CIA2c literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/all_loaded_constants-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/all_loaded_constants-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4b5ae51218d66211d6e5bc1ad527711057b19a5d GIT binary patch literal 502 zcmZvZJx{|h5QaOTw6qISDJ)x{nU;f)O^}>)3sydM(C4RnFTY%ow73WU6E>YPYAIvJy)~tHOFAi(ooZ4DL zRe00ml|y@tltryTauy2dzJ}QXSxH$f@yalVYu!l0w!#)JMF!mqmKE@YEJ0KZq(;aZ z=1sl#$UlLfH82~ukv{}?64d5dDD2R*-%@yyKVG7(wK5D8n`;dXqnzDKFlMsYkuXX= zF|}qllJ{r1kQn(FQY4dnf4|AE?pPm3+WQ%9xV64>JAc3Txw||$_(6_mU)7S3OSzsho2g`R%=bh81ud--iY5^i!Xw`GB=pZG zRMUj6F}VreFi|jlwv#*ZCKGa4l(FDTMc&rxQ>yRFf)KPSb0+NpIUE;MTeEns$mwp* zcXU~4T4dhn>B0;BkD;_oODYJ=*oqrG7_b?GrIN-{Y4M~WX5h*IS2Ifn-pHH(r+g)- zy#K}}+f$=Xqkdaxmhwk{4=_i~JFB@|fo8u-t{K$90YI2mmIbvLa06T#o-k+{(swag zTmA$5lj)dRp6??Iw)G3Q@W6#|<<{CP!3z|1Kw2pam4$M4=u^|QK3KCi5B=_M>;PAC zP@T!qI8{2QHrPO2sKR1`L8u#QGC;Yzbsj4LpFX#Ug2$TbHAtE>Q}t`y-6(XgA8B5Q zt;mr>=xnxNuswC?rS)zMQ>A+SrqB}raz(W>?Zs60nrpB5UYxakHn8=4h^cO(j=d!( zPN(J#{g;3D5HBmO(X%c1lNqz6MtG^PhjLZ1kNw5Cp+uFZ5r(ujkl@rswBQY5WfVmsgiNzX{$? SmT&4^zjYH6Qr1woTrr~H(tgN%)DQ(H86bnA>X2%hww8I_`k#n|e z0X9Wzorz(bt?t@Wpu45-)>ktrFQ~IY9}PCPKa9Hd)ak&gnpzzdLku?R$~gL!%S|q~ zdAXX`n(c3DhvUdfWsC#cVXB<1Bff^q!Ba4GFwK124c`95VECZ23p-n_&C)7&ETFR2 z=$z(xn1*jZ<%uL7%71cj>(!D?M-6T%-f{UYtLX)MF3TKw!KUP8{H{vzxQzEbhyNV_ fzQq)l`ZBSr{5;sz`B#YIN@ctAYvDWVf4sCm&)3I+ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/load_autoloaded_constants-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/AutoloadHelper/load_autoloaded_constants-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..833524cf9d2bea0f15c6a58567334969a71d4c52 GIT binary patch literal 497 zcmZ{h!Arw16vlUuZf-{>f({Awq99vO9@5JcEe2MVp{E|oYn!fNX;PAux&Pi*=a3=Z zLf-d%@5lF!1|M|1eAGFm_i7t+SLq@di$3!&rG_Gf*6HrSi!|5DI#AAf)O(7Ue;0v) z0=DS<5j}I+aC7y)G4!H{j+!=;BG>d{w>Ji}ZW~GwqOG}d13H>FV4O_`nobTiZ@6-0 zpsBp@I6=r)rW`j4Bqa-^w1h)mkzZ)Chn^C`O5!TRp&%AY?zTi&0-Yeogj?c;-aGTp zH<*q(oC$^FxOMz<+Rgs3JV;RMg;2bw!(qqcG5>VQU2BvjN@IpveLLxJUJA*XKanDv zmAlqvd&sHDx_BDQbuC<4As`xUS{hxa4l>D8U3TR=?8c@UmwFQfLDFM>|N5r0&QI_f XCx=JC|0qA(mG`1e4Kmh6D|zq*s<@Avx6ofMrCDaf)ghJ`2EbWqLepy`72sETaNhc5DNtPQC+0RHaCI7w-9@_P| z`|i72e8KAToh-mxcRjj%rn*}Bx#CNM_L3u7$ABHA;%kW!YrF#NgLhp%#7J@d*V-{D zq38z_yd`*^pht|Cp$8ZrhISk+peTEcIaM>bFB>16;!nYwZ8O2Q?nd22!*=WhqNLVm zeRf#;?mOuwQmZqX;50SbQkO?$(#8e)5kgcm#pf@tw`p0N6o2?9I)>6dPEsEfTMYYv GDT!Z@#Zy55 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ClientError/cdesc-ClientError.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ClientError/cdesc-ClientError.ri new file mode 100644 index 0000000000000000000000000000000000000000..e4cff87c7c4b852c14208e3a487fbe7f0c1794c5 GIT binary patch literal 517 zcmZ{hJ!``-5QaSzS#>@r1X@Zr|A5A`v>4I^JfuU~Od5fv4W6S>sqc?n)f|hC|sm>E3KsQYv-&(1g$qk`ncha*ZhZ&>lj54 zTKt7h1t41TbV6^rI}9Bm;4`#<#AK3p-1(j%OJhtii%60;N=vZNs#-QDo23li&#pog zy^}1rt@7okYWV2Tv& zM%<(uDy>AA>OV^s!HHR1q=^W733Uv!m`(r;DmL;Mw0yy0GVh%AQg~U1A~Nlq`r=-O z2ehC}@3|3U3unX#o>yEPyyIhJ6F@~eh2#!MfF2b(4G=nmJ7Q>m+3G4x{Ot*OgIr|| b!z#)y`@GDb&w+RTn!pne*T22B^`PZ1%SV=5 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ClientError/inspect-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ClientError/inspect-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..59ced1120298e01ec16de9d45d73ff41bafecae6 GIT binary patch literal 253 zcmYk$F>Avx5QgClMG19>4xtb_)mhr5(R^7P(g-}HLrEtOLXzc1RMwf3Ov%5mf+=)8 z?t6G|7N4;EctZoQ3zwr!XKb6Lo7d%?3vsX}F<=K#mrp{GYSjf`@0|_lK!mjZ``I!f zpcqE&ok4hk`H4_D@1VmuNS!)_qa`;O|q;=tpuM^Vi%N`#57|7Wc3JUC+bq&9eDH LJSe-h%6st#f2&nt literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ClientError/response-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ClientError/response-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5a33073f0b923f898f30fa0249ba734bb6cb78f0 GIT binary patch literal 253 zcmZwBF>k^!5CvccWJQIlOqCFu*-PeQNd-j800V-F!8!-0SaovI*%9L3V~E7W{@(ZA zFge24eoZC7ZwP#v*rbr3YnjtE(XuG s`SYq`s#QSkjG{`F)PzWSrH!L&nrGu^y}KH%y!`GD?TBl1D~H~vcfb2n8~^|S literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/advance_io-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/advance_io-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d9b061b88ad117c033f8debbbc8d1e7b55f8356a GIT binary patch literal 272 zcmZ9GJ5R$f6h=EBx1yC;A{N9FmUf|@ZS_lQ`7E_Kj?(sQ(_LEQtAg zoO8AKfa3T}Ex?n%9CSKSR~Ke3%Ny*@=v%D}F<>u3mTQ3lJG=nw$qf`u(npP*e0%s) z-7z6xH3W0UqzUe(?*oRfaRA7m(P^I+u&f3QDb_Q%u6kp&Ebpypw*7?Ij)NuaGW#(! zY{%Y#SL94mrwlayGpat2QwbZZ74@nmpYm-~jkfg7Ij?83oUb>((`uRBi+{>F5bf;lcP-^{ zKt5RC^Y_sAB7LN9SD#Er>1SgHp%zLw$6rHQ7jG737>xrjS5ox#J)z`wSr_xAu%Z`F zl>S|31k2fd`%QM9F!I&V_s^^Eg#8{yN)aavQu~x<)hMiYoEVm*EXALG__Oy5qHL@f zw&9{p&(T-Ww4$dhg#TqmhA}j-(!@G`R=~^ zZZ@CLoL@)-JWtn?$rl>>#;!%X)sB*>pnBz^-EoXK;1%FVK2WmRoDB}*eYdm@73WZg zSvji-?iSz)0`4&WQHjS+yS*_} literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/current_io-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/current_io-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a7eaa8542ef1971564e83d2f9869d8fa23672636 GIT binary patch literal 272 zcmZ9GF;BxV5Jo#7x1yC;A{N9Fma?>-uS-zDl81s+!IZ(eBo4K(bC&IZ`tLEyf;!)K z@4c(V2NcI=Y5|^x^FgN*b#-Cpvb<@>5cH6gAqMP4$Z{<(V25XbJvmR&Bz@G_$+w4p z(;X86Rz8?-Oq$?sVjnPkjUFJ2Mwg)rSXLfGiuDYxtKL{G%X@2@Z9gftqql@zc5gz% zcI+K^Mb0F3%0e@IM%4#$Dq&-_qF%K$q>PQK(UyKV=k-jM^Y!E3YqiYn#YJ*Hi1v1h Nd!^ve?k&d1e*t59SwH{) literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/ensure_open_and_readable-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/ensure_open_and_readable-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e6d956d09249faa85ee9f1b8a8f4ee762a5b75ad GIT binary patch literal 299 zcmZ{fJx{|h5QaM-w<2rAQn7>u7V3%Nx&#$0Whh8hnKD>*;;*|2?jMnbg&N%k9UUtpBaxn+R(JRM=8+lM-6w)XH+M?Bop9@{PQ{+=X%hOer{! V`j3BEu;Ff&`@mp@*%=Wd{RQ!cWAgw2 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/length-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/length-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..518c9fe88e4601d1ad9109744b9edb1539c41065 GIT binary patch literal 263 zcmZ9GF;BxV6ofk;6rEY$Ps5>&9{p&(Ud%3#@v(^%MkmhA}j-(wUe=DYju zyV`t0eSF0p;Kg4KI!`!swOR9~vf7{XM1Z_8-aIfF literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..cd735da94f7269079d5e2d1600d753a82183fd48 GIT binary patch literal 264 zcmZ9`u};G<6ougqC`3eT5es7R1Rbd7%Mw(GLMKIKqUBZd^)4ct_Nv0AVPYt(L7?cFq5!d@DB4r(SF;1xNO z=ma&c<8ZdsuCP^!-cNsx;``7c);rCXwHCc=^!lPABrO!kWY4*R7wMn?zEEgYItBC zT8*O270#?Yx#9#H<@34=RA%q;J~a12YRIw53pBp#?s5qlf8sdK&UkeHI252S)F}N- iF?boO;d<(!$yK-6^xssSkQUd&-|uJ}p_f`X7ykk_HGW3` literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/rewind-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/CompositeReadIO/rewind-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f09ef4d95b5f6c3368852e5ddcdf9ecf45602f65 GIT binary patch literal 263 zcmZ9GF;BxV6ofmVv?6Q7Qn3UESg7aMC8%J@LqV#_l)wHGlH)hG&I_it@s)FjBvi6aRD3rJY?9c^FChLP1ihVx()wUI- zP=`rcGa#&Ipycox!Xjw2t?=YmaKYKs>_NWWn1^6B|^+SNt7`Da@KI^4~29~hmm IJ1bHmKZ|ZvSpWb4 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/authorization-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/authorization-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7294bbf9984acf20567ccf31fafb8ebac9d6a61b GIT binary patch literal 1003 zcmbW0(Qnf*5XSd_vaziop}`AiI;GMAQkNA054alYT2@iSrfDm@bSSzc&T7@MgY5w2 zug8u%)DE7=OBCnx@9w_4ySMe3>|MT>86hWPaYoHd=F>g4ISwCTZ9f$Ig@#EHkl=JQ z4i84CFvkTULn#E!+^_b!uosL*WT&cA&N4}!diEKrd0i1=1JxxJW{d3fD^x~LTar9m z*Id{THwvp+(7Qhk#^I}rhDG3t8Vz*?2wAO-Ea7A|Lzq#_sfvSMF!_r);3(#wn4lZ7 zx9zyLz>Zl|6yOjhGYVHmF>wQHrGOK};DF=s+{if<>uRas1L_$xzhZ!sTg-RlH3g=@ zpu5DGp$a))bO1%}6TD;07phWgbh+tkK1NTr2r4p}(;S#E5;9qq2%1{&(AdK{T^#vf z6*8q`TU#(8yZu6{5>0nmtTnN9`V-5FQ|$!(2eP;8BDJi$nQdgeUN;#~R8(~!Do4rN zc<`n;d>z01`0Xre_~WqMT=ItNX|&dd=H9f$jzrALL|nIl)CUzu2?O{2PfSu&G2Bkfh46iSwf!IaZP7Kzmx xyDK_LDVIOG-R^Y5uH|z#l^vh@i>8|gb}=6g|G@3pD0|{}>fFr%A9B>X`x|~ZH~jzr literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/basic_auth-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/basic_auth-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..06ecd0f62eae69bdae5556a5ca7c003419e1635c GIT binary patch literal 754 zcmZvaQE$^Q6ovPIva&H%pur0Wtn?vFDs40&9$Xc*E6a$)s;!J6twNFG+%#s69oY`u z`1ROH#TfAFdwkCE=lh`Z1@A9DNQ&`P+@69dWVYOA+p*tGiDon*wJAL89Y?X>i-;l_ zxy5)Ug#c=p6um!GBQJ{ZZdIq8QHh_ouBSv@*A>P#qAo$04&I$qL>ax@llaAb&6)LI zDN+^Q=;6{8q6#vb!wA=X1cJ&8 zGUScCi`akM$ZTVH_jcfp{%LT;iMam61Z>IC&Zb4c<%$XP23^>6hr_wkHoh4RHueV< z(Hi|<=tgU)vL<%Y-MD+Pzju5?%8G+_eeB?GZkM1^n^kUGB%RnFP>X(W2OR}dPO^-N zppODsfj}BGDIu`!-IIHbzNMs>!994vw~c7nL*w_zKXM2ldaG)^X6vyL77QM&&< zc2X5l@Xglv&F{ULCwohFu=uEJ#?I9CiriW^s{^rHrZ2e{vZ?5R&fuFfLfwEiLAE@RVnd+$kKh%eT$vUD89O`FKE$zf zLR!Wmb!R`LU4zqLsFzq1xHZ8~Pi70ZC_UK`>rp7*$#8U{+a3KL>2~;M$a?7_P(++I z)MB_ZP(mKg0)BGMp5?7J9lGq^Pe^OJAm@#;k0gR25Xw4KH4WjgN!|)cW%^bMe%g-1 zJ*^*RJ2QM}k>$D*u38f|0mW9W(Ou<`OR98Rg?bmpX)8`r|H`s#wG$Ml5%@y{J%;

    -=k!vY779*e=&6U0v~SnAG^zPu?7uf#2Qob7 z<;m~)I0?S+Wci{>jGyFo0k%<9G2y3qG-i&AifH(8U@XGuHOr&>jA~lZEyi;tC6tyc zd3P*KP?q6Q=a}H7!dE?eLG{{o7<(hvg0ul1r5)AQ6oJCm$C?jsvC_0_P;yqFJetil zPzxrcvI zo`8pG%?0Gqt>A1{_l;-X`A~SO+0F>ZscN|;4bY0ql_9lOEwPjdAgU%_Z+%lk7znkA r<2(v{+TF)ukVoea?SAXW-60+OX)pd3^|!3N>{oeLx}{<+s4?*`?m3Jj literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/build_url-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/build_url-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2f2644f858d43646b55967850f3954ac189b69fe GIT binary patch literal 882 zcma)*QESvd6ovaB>Dm^3DS}w!Iu+@{l7zlF%i7iI!h)4jsxPaAo9xYI*vU+snYbx7hZ9n|Kg+0IDfCM&&U;eKHC@DQ}!gSg`6j~kpT}rO{R=Z z(BK@eIX~4(QRakJhqur$m`wO?Ri{#9n!o5g&(JLEigQ1pE=jo_-yK(IoSpSFKlqn9 z_x1~eRS^sy&wPN3^VW;QB`(PVf+2}c{37s~AlIfn`dO28fNBnzE>odADIBbXE5H>5 zbIP%n&O$H@E~o6ZB?nryud>Y+Ae42eG71~&Ua$`m)$+5q-nzHfH!`WuRBrpods8-O zJYfV6+*GJ&1-~H-L-@1Pg?Zc1p)A>EQAp!6)tFW%=&jn z+zlA5`AyC@opNpe{b74H0N!v-^5Z_-Zt%bM%{B79v9CgjF6KMqTu7R-mr|rr-jy|K zMt5BeP1*|Lu`Y#63c|Ti3!CIdmx;qvQlj(3^UfF5CMik1isN{;Public: Returns the Faraday::Builder for this Connection.;T: +@fileI"lib/faraday/connection.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Faraday::Connection;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/cdesc-Connection.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/cdesc-Connection.ri new file mode 100644 index 0000000000000000000000000000000000000000..171a40726540b4e822c33c9b1c5d91ac0f70069e GIT binary patch literal 1725 zcmaJ?O>f&q5Y?feRN1m@2dxvN3O4k?Ko62`1(tEj#<3d#b>rGfd*Fdsk|SyBC70P< zT1tL>XGuzwKbngL&&40`NBbWd*c3eRYZcvlr#y6EK_NcvW(4vm<5moW~>l~(p-SHFZ{zt-Tw_LVuq(}+wa8vB}P)oDS3j)VFpWbvM?s6qmeH3 zf)8Vvo^-3So%;9qnEZY|B@e?!8J}~->!2f>WjF^zPAdBv<<&7ceM^qtY|>wY&Sj?I zt<6GreWWF2W=y+2G6NI$mEh56R*ijRQ7b_VRa8D0`!eMwTmVauMIFwROhdyW0im3Q z7;kX!I*dTb<=E?uy}fbJvpnoZ1s4gZy1DBTZ6`0Mje7caS_?3!XC9)Ym=GYsN)Kzq ze=MTczwq5Movjd5Ii!i}l<69$%&o|ucK+}``1c`pY*hL*LPu+{-R355zfdB~70meR zvETVbpH;hYhNT&nnV`>GNZjT5^ux#ZH~0d1dc7GWM%A;SbSq>$u6GT0ZY|l@zmXf1 zhMW;3PA(y-q<@D>)ur&go8NQ07r#6F_Cx#D-sfc*zohnJ1Tumy2s9fzzi3#s^5TpT<;*r^4>ixe@<je0%*uRhpZ){>WA7iGq=vr$fxdH0A{w|b1CS()eimD|IQ8Lco6pQuZ$Z literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/default_parallel_manager-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/default_parallel_manager-i.ri new file mode 100644 index 0000000..092e198 --- /dev/null +++ b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/default_parallel_manager-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"default_parallel_manager:ETI"1Faraday::Connection#default_parallel_manager;FI"W;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"CPublic: Sets the default parallel manager for this connection.;T: +@fileI"lib/faraday/connection.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Faraday::Connection;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/dup-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/dup-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0ef42d6ce49d01a231aa078918f935e615918273 GIT binary patch literal 416 zcmZ{gO-sW-5Qck@G`0spiWiH7^rDwG=gGlnG!U>NMNc_|NwR5{Zg#@%2I;?dLqrkv zILyrRew?^(u-H9N32-NmTV@)nvIU=}zFYO31I}ZT`pX0rR(J%6NlI24PI5J@LnldK z-t~pxCBfy$*`hl19e{=QEtAHDdDNjYI&%q@KW|6IMF|8Zaz)m*UDzY@II z)MNTh`4xVxia`#7h+1y)hGE6!Ugx!wKykLUfgCNKzsXx8G8D67v X+w0kPokNx7#aPZWsTM^nQ0w3WR>y{R literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/headers%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/headers%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ddbf423a3a05338b9b3fb4e8f64439ab72fa7ccd GIT binary patch literal 363 zcmY+A!AiqG5I{Z1S}p3Ocu{1H7rnGOPZ1)mp*d8F)>95)l1!SVo87RxQTq388>o04 z-aOvS>EH`SA9Gy*ysF)jT&>G=B+ioHvL-Ca*cS%uElz@m7!8)V1DI*0sBl87$0IXk zaSX$@%cUqZ-1f#Lnr+ttczxH9aswDfEgEN2rs3{Cv-0+h!M0}8^OPmQe06XE|0HL* ztBEhr)?8P-Q=|%AQpp$V^@{fid`r8@H_DE9i^AA3o3b@rM3s<~1ou+pldA8Z6vzCr z$q!f<=|;G0ZxU)_v&!fubC^rYbd`DD`FNYrgDHsxtpUc)jA#WZsMPFNo%H=5GWoz@Sfwuzm45t&2|7&B_-yT zD|vI23%xjoLEU76=L$w`^PK5zQv*0mQ=zmy7(}kxnzX0j>NvA>gpFo(>4m4Mm-vh2 zp$o_iE$WI(B)lNDDZCZ>WJ6MOBkrn1{F;6)mu($P1Glb~W4l-E-#wBg3027%UEh zB)qu$)MD^}WWhB+6~fdN)Liiq8X)bTV+0Ns33LetUmRMphru9t`~x|YT#c`V!j2wv zzd%=0tpj-c7g2HYaA9ETi!5i`poW%(&TK>}X8$5m%C=2UtWm4zk)+WAT?g*iF zl0+kM<`i11Nw{{8{Yck>(h7Ou zM{QafU8lq|iK#AA-%o!1HqB7#*M2_Y`85Y3??B&5nE>Y<;O)k+}orRFv?Ds5Vnl}L*M>4n3}%X))_vA4DtLVtbj z^=_avRXMD%_syF(Z)WyM^%l-Dqkl7el;M9#AE|- zDTSaj!=wOk?|YTO1Zrs(aW<3i!V_H+wa8Kc%bG2zFjc7aQ=*KX)+D_A6Em{RcZ#I* zO7Cb|3Gn$S=K>T6W*Fh@7uAR$n+rW6qHP6C{^I=1iC7Gopa-&dT=4cY#gY59(Ctlt zq(Wn(n7Bg`(bQfIk&!5~e~C+%Dw?o+lvo(y+$Y&9?gv#7F>HD0bw5}1XGXQrs4i3I z58;irOv zlbxWe$z+5);9mp{D2&?4U)~g^l)2u4)@9F1spIhw?ZE(2CGR(7Ynx?bt*2#FuFIo} z;Jh=|jeI2X$DU_l4#$X!6;o2UF-9w*7>PK2Ftf1@w@qRGv^QWyrq(W0Q@zFaaBx)#~l z*I}aMGBmEHP$r?p8(XIiBg*Bv+YRuMraWPublic: Returns the parallel manager for this Connection.;T: +@fileI"lib/faraday/connection.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Faraday::Connection;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/params%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/params%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2067ea02ce48fe4c3b039e5270572dd3ad2293ca GIT binary patch literal 359 zcmY+AF;BxV5Jnl0DHOp{v4D^j7FgQMS0M#jA~FoMxiq3LZ zBYzgQ=2Y?ZD&g-Pnx1zWbwMSTe2e|$L#PgUE2ObwHf3*c5>--R5?m{pPpZBAr1*6o zn|v1wBWk3}Y80i^8=F;zn#_q@VMbNv^UkZ=EJsD3VHlPR*X`$$3Y`#Cwe z$G_l527LQUIq3+uSBG1HJ^BPz5p<7cXsxC3X;!_#K`~wtT}j@OakBf-{e^6HaL>yq zBY}O*Xgtl@8mGx`ixU~wRM_!EL3Nb3*ec4TC?X9pBaz4=qt~WC6~%;!o#QxRC$P`Q e4dq?E?~Tlr28ZLAnV*c>hTnuNfXz(<%J~MvPobRv literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/proxy-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/proxy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3c13ee192c08605a5b7b9763b726f3451dd97195 GIT binary patch literal 343 zcmY+AO-sZu5QaTSTz5e|EM61|^`e*EdYvLvcCGfXviNc8p`>lv2GdMQQndfxv<1b} z!0__SGwCdhOaNw@t%FbXBwoF@-5QNMBnY}|-nzc0vjuR4lcl(hA^od(T zQPa0!+M3g6W@(>4)d@Sk~>Q&vUNF`uJd2fmCnYPA7UeHT60ziRhhKZ z*rb+alBZavE^nQwNi#0-%lG}{Aok8~n6BtORYKkljPS&jar)PR+eP{L^v?_GhRKa& G#`r%$;%}S) literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/run_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/run_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..896c818fa7c7fe0423ce18891436587c900e4ea4 GIT binary patch literal 637 zcmZWnTWi}e6z;?D(iFBmlrdOY&%D7dWJ#VC2JX$&u#S?YPkAu1eO!ykI-V{o{`Zxm ztm~*ArBC1OoM)pOcDOvJlCcxjU!iTNS|5t%S^P>nm23R%(AbDY7ikuMOu6P2?-@HI zrLeSu)Q88gMUlpJQu0>@>>>%m5wq`vhcJx2y+6&xj-Zjx; ze;sA<*Hb5CWq_*+ypRFgAUwEO26xkF5v`t3ol34YKZL?PT8sy}{Ve{}ZUX{*gOw-x z)wcynxLmESA-qgs;L75O(-MZW16nQAEs%zrWd@djmn9nW7kyk%)jvURF9Y5826=_r zc)Ck&8lW1SLRC_QRgez=*kC{V!=*#$xX@;sEP1gD;QM&LMC-Kgfj@4+bfgS!!EBt= zLSh!blcJc_VP3QHVO&#P43^kDp;p*@koCz-UTbP|%L|D))w#!8KPi(JDCurK&*G8a xgyG|Q&ztxh%9?<0X#zve3G5Pn89>P!zbr5R?TEii%hzGjKS{S-o=I-Z{2sxc$*TYW literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/set_authorization_header-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/set_authorization_header-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7e5a69570943e2599bc9a085fb6be3fd6724f747 GIT binary patch literal 308 zcmZ{fu}j1-7{zapc-X<^5JVKIi;8%0{cfq87CM}R=+q&6Nz=Pvny(}&QvZ5$7Ibob zy!U?Z9n9Zh@%lsx;L(j69e32!3v*cI=Rrq-LlV6C!f42eoyJCc2JE@4@`n;VHaG&T z$vLg|j;nt&D^`|}^@FrV5u8oL4f>Cv2T1s#(=N^-D|+-X)H66LT4QyUUsxlT?SxvY zU(&soY{lMy7u1>fv&^_{5Ur<9M3hzwYDMzL)Ek7^{mQIucsd(j=jFSyhXna bH~X?8OSg{y-XyJ5C)3my@*Uc>#Sr*6K~HEe literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/ssl-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/ssl-i.ri new file mode 100644 index 0000000..57b3c56 --- /dev/null +++ b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/ssl-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"ssl:ETI"Faraday::Connection#ssl;FI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"/Public: Returns a Hash of the SSL options.;T: +@fileI"lib/faraday/connection.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Faraday::Connection;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/token_auth-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/token_auth-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7d0d72e4c59ae2434255f0b8ef37e032478efdf1 GIT binary patch literal 757 zcmZWn&2Q5%6yE`5UyNM_m!a`+4*{v`a@fgLQASxsBnHz~xU?v8Qm3)%*pcI~jlZ5} zr`s6#6#4!9`^tN^^_?DEebPClXX@^P+fpxP2VyfJ`&O^GN?B{mfClH2g!CrNum!uL zbgY%)xfNRV{z46d$%O9KZ6-yo>0!ru!OW_yDMg94;>vE(-MD7PHnTlVUq8iMBLC8` zx(tTfvmhbkOV35&n%f528f?ko3=L@`elsTzC1(q6;6~WePnY5sSKv(zf?+WIPvfIx zYV}1ZzM+RZP6wmD^>_d{hAApsTO-tRO#+T3A*Z@_dJRIp`7b8nGiyrF1@K#ISOTt`GOZ=A84U9j6Oh^ zF%x0}=dS1BT^G$Pd{R;P^B&Z5&&bsM*3Ru{PCD8->90XY*uuj>C4`{PoDe^!&*MUy zirMHf*~=?#TZ7FgZAy$Cv`Gu2 ztJJbg@>CZo;w`RBlV)7%n<$EA8wojl=WFTTR}CXjLcaICzQHZsA3vzz-6Vh2?bui6 KTaG1bn&=NC7VN+P literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/url_prefix%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Connection/url_prefix%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9a67aa8b3044aaf33846400eaeba68abbec39f84 GIT binary patch literal 941 zcmZuwO;6k~6y#6^3Pt6BDpgd~tEnoGXm-WXt8JH3wu%H5qR`78A}4v-SU7fSJAA0> zfA4cP0$Rw?nVILAH-5Hq!8gyonw;|keS3nwGR16DE+=fGwJL2amhxsC@#tupu=i78 zMImlEKQvln?xoS&4`HKdI^}Ckn<<$azO~Rj5%#ieIHw_PjoPp9wMiqace8cF-~5X? zr2%s*nkpJSpRFWpdfI7mpdSt$_zGbzucV#>&4p{}E4VmIKm% zi8d2n*2|>2max6x4aV@qzG98n@EhVdhCg(P5Y8Z=T|b(M@Mmw{*` z>k02Vg3Bwc5xQ?1#-E_$^bpoT8sV$HL(oCkLz$?@e(SJv^gB$;xwP_gBjz~XXS+la zd5$iu{>d8+7KBcSznIX9YT<|Xx$U2!Z>?Swhf3$L==xGxQ-jAUlnFIeqG^5HrOsC; zrBs-(w@PM%a#8p$p+(1{GgRh!I2_KF s683tBGTsB!xhc?6%37-3ZlR1G*UQ7ZKGNAVf3iyvgYPreuna#jM}c$id%BIPg;O`?^;4)Y}Z8R0U2d2xZn$9$<<%xH70Ewv^AO? z7lJS(NP y+cc%gd1s{O(8_!Kef2)Y0ZoRtaoM|GWhZga)88HAFXw0b5niloK+kn7m3{&XvyUzS literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ConnectionFailed/cdesc-ConnectionFailed.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ConnectionFailed/cdesc-ConnectionFailed.ri new file mode 100644 index 0000000000000000000000000000000000000000..ad50f2e9d27faebb676edccb03e0d0133bb204eb GIT binary patch literal 426 zcmZWmO-sZu5bZ(IxL+4h5y3-$fZOxrQdqap!+KEnltW3=RD)@zq^TeO-gLW*f(#4{ zZ|1$cmovJDtEUH)0FUTeVKzqeJ-^VjNG>;Mt&(1&&4o6qCP21%k=*6NiCTOE{99lo z;5Wax(aQR*bLdEb5N;=_opA3%2M~0JHf&IsXPt1q=LA_y8RZeovLL@*#JU)tKt0Gw(QyYVl*MGlchxK684}B(o?*IS* literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ConnectionOptions/cdesc-ConnectionOptions.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ConnectionOptions/cdesc-ConnectionOptions.ri new file mode 100644 index 0000000000000000000000000000000000000000..51e6d02750471100742bbfae8b8a56d0b6336e82 GIT binary patch literal 568 zcmaJE4`8qSG~hLKF}ev)>89U81cF(#$T;R z)SDCtkE>xPuVb^9gpwBvr&|>Z;okcW044RUG$DmafegVjVri1nl#O6qG)l`dJJqVX zX|`H!>{jBnt0Eudg>6;f@l0i2J#UAHP#b2KoR_(WVv$(=N05S06cH!%2GATcfJfNNO4eR(_zH%sQTph1zFftujLOv C@32Y$ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ConnectionOptions/new_builder-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ConnectionOptions/new_builder-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f9c6b91f36c0e331b33b1161e25d3d2f9f632bb3 GIT binary patch literal 280 zcmZXPF>Avx5QQ@oHN+V@ge=+IrKON)zAO$&1Rl~tX(tcjB+HG6tTU2K$iJ_HmqM4f z+`aF;_b~m2#pi)Ez|P-JCY`CS7WT2spS-zB)mvAazWupD&y$NIj<&VK7Ub;^yT&LFS234@?Y=a RB=mA@_)eikw|5vL{{_8HT|EE* literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Env/%5b%5d%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Env/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..00f481565f4199c149f5dd45d9c4af3127c25465 GIT binary patch literal 285 zcmY+kB1I zg82lj(d_#Uz-xUgvsu4J*O zr`HSWoFr{uO>xS^3ANJkMqnlN&hpw&%N-U z?(R1Eg6!~tHNcylb}Dq(@JuflUGQ%LWLq+tmD0&ZP5@i`^AzO`DN9I)u`;?wSk3XB zbmwsZh^(4t249#IUUOxt7unl_44_JMcFNLmw9J<4{o_q+7<7{S*6>O*5{{5Vm!Vo-= zp7bQWD|*Jo4!FX($|_t=hBi#tQBVs?ne1_ESPR>fl}y=>(#z|I{3&J-slLs*>! z_R@ci13*$6d+j2H`DTzl29d#R(;2H7unqPm)}LCo#(jjk^Vru>Hdfcz)e2oqgQ0G; z#cw9EQ{*B~wB}ge zPXu3_aG5X@2is6)S6+b$9k-jls5FQdrv$u9oX+s(xtcW3ypv$*Oju3&diAWnvv=twsDRPrbYmvmkb~gGK z_|=?~cFkUZd`RN+`MJk;&)s8tOn1M15;3J;gv?oXoH3=sKDPtMJ}Is&YMq=0&XZFn zS;FR&8k=XK>Cx}6rRJhgg95H!(H!(lByR|vh-8kRN@n<$@UsG?SAWqASOQYLA?Be< z8Ltw-vkbB*X9b&rT$pn7LIhP}5NQ3bFsRZ@SL!t~8VS1J+~b_dA5}>yUaHEW&^F!l zF@jd1CA^O9+2I=9@Kc^a;Ou97a+o%EI~0ri$ce$Dt}k+~>tMW?swkBrk2ITP5Q#L3 zMWGQ~MH9%xwd<|B-i8~lh3jM5Z+ILdZOsZD_V`-hJjJCsa0bOx&zcmHc2+69=i$0b z!rr>yMSQ>OcjEiya>w3g6Xn^kP6(*)9LrJZk64T**2~+m{^IvwM1OA;U~gE(F({Q* z*%G3`Ke&Vcpxb}pch74X)%1}&2i2gzxQ+gx*A2KO==0lBxWEceB`Y!ScGwA=vkznl znuwHq9*r)@708Jqdd4)-^ODCX#yL??B!m$o=K&!>N(xag2v@kLNh%~ka-+cU^b8b` zh1OBDxF(BYzHRDF8rd(;YC+tAIozr%W*OzvG4wWK(}ZR}M7ngdtR@+cL(A;-a>yqj zBc#xz<{uKqv)xh(4Y7vAfYYr~@++pnECOen*9whc8OqxZduF2(UK()!$Smye^4)6H zi!)#{GHF>E`*Ec-c1Odlu32-o&x?i85PrWpv4x>axI>GY&jcR}wGwr4CsHv7}Q6~4bmT0-4W@5m0MVYJ%wAkPTurptef8H4@3W$eM zXjK!eX51d_=Qsca_Sj3~BZ%_>t#=h8SpUx)1Ndxl=va1Bu`-E|7Z%Id2i)eZ(y~le zT8V8t8*FLtii~@<;*v>o>Xql6#73F30)byREX?0a5i_Oz- ZHNOkPqOd0%Mg1^q9mw{mUo|?H{s64nERVkrX(3oJDAWeI{t@=$~jOc|_m;xrbvFR~p_|2>9GFrM_? z_uf0s-eL9nL@mIBJM2^(sB2bw!SjoD3X!a^%1Y$}1GcSseqE!-4i5lZ_j&UVDOp{^ za-5{mEx~%$?$CcsBS6ZSta34fWi_IYpsg-+LSfR-QDB=V#nStEH>5F8oe79@{Y!2$j7Ik*`9p>ugRGt z&!~FizoHxhIhmBUC~1%#`IMniYP9sjId4}@wSKtZ{P?%7%j{fa)f_~3yBNJwaLT?~ H6(j!zXogbF literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Env/inspect-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Env/inspect-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d3a6a879e6cebfbb233587e62d6bee4598eb40cc GIT binary patch literal 239 zcmXxeF;BxV5QgCn$c+eNg@n3=1s3Z0x&%QjWhetGQwHnoIMl-NS+)b}zsD$IJbk)H z?^X2yoA+1J0MGt%H2F+Jzp?ACxv@S4qca0`5M6U8Fyeq0fP??O|KIjZ2&luXoYe%| z1v+BoP#Vks<{V4;~`mLO;(4@C%-DTDQ#IE{tv7ugP|{~kjY7*BWi z>FzXpht=CNwE&OqxKnYUu36~?&#$bqQh5plVg_$90NupB38 zbW5E{s}8lxr`9=!a`6ct$=#h|d$?hr)p$%=^5C_%kwDe+tkLMlUFMNu>-JYU@1 a|5U5X^es!5lBnD3dDshii{{B-2*o!FHeC(? literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Env/needs_body%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Env/needs_body%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..790b19dc455856aefa59e2687fe3b7a6195dbcd7 GIT binary patch literal 291 zcmY+9F;BxV5QQ0#8;FD$Dwe`x7FcNJ%Rmq`l82(IDpLl_Nu0*Q@maP5%D=}n3yi0G z@6-FvlMh(#->?CAG1FFt9@}cE7K~mSDO=BLY^P@eWK%MFR|+RuF#&AM*ZtprPRbHe zJJwn?2&);m74CDi0Fgcp(u4%k!U`9BMG$WPXLgZ%bi(!|zo-bK>F&fLIXS>((J3t% zU1?RXyLrMIZBS_ZldDgetiVA9-b>LcbM(A(IPf59Ejf0)K@;MDXd^X#XIWOAF}iqo b{H+#O(JYBV@hF>{dDc6+LFiX4yw83BRDfJS literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Env/parallel%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Env/parallel%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d4b3d28d5fa06bd2b5b7361cd8abc96bdfc3782a GIT binary patch literal 287 zcmY+9F;BxV5QQ0#8;I1YVkuKtV4{e~)Pf#CUh_ zefQpF_5rK6S8M^E?P;gtfL*iFi@I1k;e|2EJP{yURu^lQ7M(Z&Z0*!=smH4Xtq0kq=6A+8zV%J&rsIX%xqvw`gMu5V%wZzbU27MO`fJAAYUX XGWE(*oiwoaW{$N-KMM0=L?CAG1FFt9@~1U7BsuI+N%J^^gZ*ZtprL8=N; zI|{8Dgw+h(a`!n}fJh$)X+i>N8B4*}1mX67W*5mv$8ArFi<;0Z-JMvZAP2ZCJEbMf zR$7U5H!G~s28G5yIdRJ5B@QaEUh-C%qi3DNfdwwKWZ1C=O^5=X390cr&-40>W{Zc% a-)eakmnCsfJgVkq)_O-baQ&*e_xTTNs$5tA literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Env/success%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Env/success%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..323ada89a944d0989918423f34c42076d008ecf3 GIT binary patch literal 285 zcmY+9F;BxV6oeU&8;D@47$}ojV4;sl>FQ@>X++nL@k8Qm)3r;V>q?8WfkpS6LoL*Pb%T^u$Hty^8?^uwkf_$7B zYZSt2Ms214oJN4eod)e<26;J3A45$LZvK0A3A^`l>`8G}6HfEpkwpsf4(DZOtmbrO zO|$Oi{56izpbHPaIeJ)$gNdTovNdiWMCWl3Q8rc!?1VxWQ-L5FZSk8iR-bUXxV!&- ZEicooEUihRQde`WSM-Cl&sK)OegM?8S@Zw^ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Error/cdesc-Error.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Error/cdesc-Error.ri new file mode 100644 index 0000000000000000000000000000000000000000..13086283c6c33d503cb056383ff87cbda3559d87 GIT binary patch literal 474 zcmY+BJx{|h5QaOT#Pn;R5(qJoiHT%BFOf;O;o+pVk@VTM08YBAv9Sy$aVyCh;c4zO&cq1Daj7ayg8NEkVR_OIu^;+Ona8~y zM6s@wO+Qc;s(CkQNxDw0%qmQEndZ8&PTHgyR{AI6*AX8_Vst#d@Et+k)AUM$2_GhH zmsKiveIMp6X^XkV;+RfbQs2^IpCrLdHO7(UI6UQ(zQL!*ICF6%y#0W>>}~v7fUVP0 zx)Dr`q5<-3ipBFJc)a8!{OZuykkHcM%$o#H|F4)d|NH8D)%E&-7UoSzBN*Ri(LMIQA4^Ez43hHBju&xjj9@{dZc1hP@epd+Wz#iz7bzg2OWpvbacQdz?P# F@dtDDvi|@8 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/decode-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/decode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..58244667e56cdc3a2d4373348d88dd880f05fd4c GIT binary patch literal 275 zcmZXOJx{|h5QaOTP!Yxo1|)_oz(O-$mmpC~8G=w%rVQ3OzEBH07i>o;{~lLiV|?{~ zJs0Z_*c@KD19%zchT@5JyD^t_k!$K$QwG^y)Ww59j~ZtHVKKfZ;lh462Ry)Ea+irC z|p!&+bf literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/encode-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/encode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..fd364bcf466e0f788765283a1005f0921735b941 GIT binary patch literal 276 zcmZXPy-&k16vR6qw<2PzU_fHX0xWIj*Cj~QQidQ@l_`Vej~8lT=S8+7)c+pSurZ$Q z^t-#O)d#E(ucQH9hI5PQM5bHYWm6V7Xfnuv?Rir^av7wNX8`VGde6eg{Us0p{*pV! zk5G)0a#j=E&(v0iuW1Cx6_dvyt)Qq!8B**Pa9#J-VN*UhtG4}Iu+66Qm@vdmP;AGJ zP}SsZ5+{_#4xdr&5EX@*T#mk;srx7${k{rVqrwuHV}0be;d Kv^|fDrRE24wOF$N literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/unescape-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/FlatParamsEncoder/unescape-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..978e6de1a6c8bdc23afd40f27977b19702fbceb8 GIT binary patch literal 275 zcmZXOy-UMD7{)tD8Vqhl2f-neU2NvJO9UIp5D{so49A4&X1l z&zd6?a~!mi43EolhwdxR0O=+gvLT0}p3w#0ui&8 z*%7LmjSAvII4XPgVsdOmz(JGXNl3OK?Rqhg=I^Si`c+%z&wl&ct&2o|{|`D@jeJ-D N-`N?|9gk5{^#eX_T73Wj literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Middleware/cdesc-Middleware.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Middleware/cdesc-Middleware.ri new file mode 100644 index 0000000000000000000000000000000000000000..e18f421f9f7c0a1ce25448bf4b4bb517375f15d4 GIT binary patch literal 585 zcmaJ z(|;-6p|psgmBzP6!38rPy9Q&YzN>*TUvoU|gt8n^#8Hxn+ffTvvIim38`UUVzm5gme?qODLi}_XepM&%qdN zyigVg%eNoJezPm2C>`>@HSM?+&>)L@rH{rJ(~t(FPrDu+acDqsQ02i<^K|UNNT@9s zVS%5qf$s$P!x;$`>`x~gHAY*PAaL)82aOS*%z{5;@ldGNGF5`ResXsN8F-ou-Hxam z*yKEwC2T}%jqho73Y&D($OYqCMC;RxWbx3>JE#ffR8FKT2$>WwQZYnsBdQek1Lf*b8a7gv<1%r1_zXte*zM_F`w i9fau})l%K;vE(F7H~n2KU@1QvdOsQ4F!i9AbMYry*Ma*0 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Middleware/inherited-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Middleware/inherited-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..67474b58a0c5f1b9322d28b4ccb2668de245521b GIT binary patch literal 269 zcmYMuF>Avx6a?T5MGZAHOXyPQ;4bZwXnt8-+8R8#LvSY#;z@e0MPYf{SDjWhgSe^?p#yqy>7SWw#x5~>nWH-ngRPPtNgjdfEv#Lwb9zr2?GIKTL)G) zkd2eHMtOK#&>F+E(?Bk*AuC1`GT%Ac%}`)xC$?X3nm!=d4r@%fT-n K2DI;&F8>1$Nmyb4 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Middleware/load_error-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Middleware/load_error-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..ddaa373866963e93b97da3d750312944252bc16a GIT binary patch literal 262 zcmZwBu}cFn6vuG~iAO8cNrZw!aJDzUE+^_ihB}lJhYsQ8lG9*v?|8{k`rr5PKpfnE ze7?WS;vH7|7is~Xa^}O0FO*ybLaQA!u>kSfDEUw$qs0@z&RZMY5!nI!nQcX_vI9iYCz8EZ~=>|^T8>3AH3Ogb7d2MBadu;$g-m7 zv;J~uegBzs#}su&6P%__x76p!P1?9X$FixemAw1s@H{|KFWdq=_2-(>kxjF)%PPNejE2mk0P$K@`CW+t4W0pNYmB241_Joq>_vHi zY#6n(EyK+W))>CV0btTcPkmZJRty+YY!+}?bkNkxs F(qD4jQxpII literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/cdesc-MiddlewareRegistry.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/cdesc-MiddlewareRegistry.ri new file mode 100644 index 0000000000000000000000000000000000000000..f5ba1a0afc616525e8c87f948f180327b277d86b GIT binary patch literal 686 zcmZuv!A|2a5bXiEQCpB!z!r%;SUKzwa<(s7?QT&HMTlKaIYdr8X)T;gWIGG}d+fAb z1d1%#vfs?S_r`M)J+bBEFRU25N7D$sM%in~&sCJg%e9hH!;3KR2peUc*%3y5ud@3~dJ89z|*ft^Q54l4?ZHPYEY~v-qm{Z-`b} zSPS+hAZ(V_N<$W(YgOLXdv7<3k7oAc6goAL&;#1XHC)x^*seF;o z0&rP_tG30v6(8WgWJG$1zR)P-r{MH^K)&ujY!zb7aXOXsU| z&$-+D!0z-x2H?G$DohR8dgs?={@^f~Mz-GCfL9ff0s9nXeh?}ut0sWze>&mW4=GMh zH_VX<0a-ul;0?j!VyaZUj6J}t9b4?u2C|}8F%9(!wuSQn%ltlg{pJ?cYt-z>zJV9i z`Xn1v)_3PYx=5`|N(YqWq@ga&XM@xj=*l^-S7p9^zTouoM;F-~zrSssH(~Zm*cZiC Kg^KJLkpBW1(Oy>o literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/load_middleware-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/load_middleware-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5079d3acb2efa0a1799d08b036a419b0412720d4 GIT binary patch literal 281 zcmZXOF;BxV5Jo#7Q#B)zI{HKjA#CU>`0k$Xm~gR|Dt6(b1{@2V=K!iW}Ufckej(#ee}&JTZ) zgHQ^xVKUye4EL+2#(0?qfJHh5>eCjoa=@6zW&^vjbDpZ=&O7tct)}N_#6f(5EIGKO z&xF?Xr%`v2gHC8XY3_8(eOk^&ZOHRgO4)3xV)uBV`RRu)v!#9iKY7_yyI;dTI0p1J I+sTvs1~`3PfdBvi literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/lookup_middleware-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/lookup_middleware-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f9bb6cbaa6dae6c809025b8e68f7f6f8f5ef6975 GIT binary patch literal 796 zcmZWn!EVz)5bXiEZ9=#Z(E}U?_tG3lEly}7kfGGbQiG}x;E;p0w#V@*Ymc>FH~8;a zJ9b@&PwSbT_ujrY&(40b>FO&*jD61QCF+#o%~YKF_A5!WtBN2KaV&Aq6wZg3^wW=?VhZdISv2js_QbfdFAGnrW8EnQ3ag|}N&)C>4xYFfjLhQ}I zckT_{R`DXW7Uvtwx4+%DSPbr3fiMV!Nb<6Tz0fIeP^~6Z7{iY`3rRwmlG0J7=hnhn zAMt#VJm1}k98YL5>bO4au!eWAPO-;m3JEFDru2ki5Yd9WF9wXs?H`^M63d3wH2(MC z7pjnJk)4|7O?-QrQCvxc&Sj&-TAMVWd))7oYkWY})n{P7UdNNHfF(rm@e_DN-PJJw z=5hCPJ{+yCbp4oX&oMtr^QwWJbpvlNTY`QY`YFbGPWIe2R%Ki}gB!3yU8%e@0S%tP zO%q(}92>cbkm%blr3kN+1NdBpjSb9kDHA$Kk;fw6mO-K@3p5WU29yL5<=X608H6Zl l?>Nrp#J5LRCb3y-y=|8F;&^9G&x8FlDgp_@=dL=SGgLl7CN7B$m$K z~&X)BwD7V}8#SQ2G?{hXMN#W&SEuP)3aa)qi1+2RpBXZ1@vqn?9iJN5;< zAaA2QqB6ES46+U6WmMXsq*gZ6#p!I28XcWE=k=n@SKCMJs5w3T9TeH*zq!<&GSO^i Ow@(UQxr$73$bSKQLSK{s literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/register_middleware-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/MiddlewareRegistry/register_middleware-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fb84ed24d3831c3cda50416c3e71e975b3dd3516 GIT binary patch literal 1229 zcma)+O>fgc5Qcj|?nhcAM4?D<7`cZwRSA*cv{6x7Xw*ogszQN7gsibWj#pWG-Q6{< z^XplEq=8Z>zSz4S&-={yoqe?Sg>8>N%7C%sv>1_zWjNX9t3&sNqAAygl$Y=@6m*S> z9Oj%3hVHuoDh#n;Y;^l-Tt%y5_rA}1&S1b=S?&uSNcOVU8=;!z8DmyFPbf8Otkus@ z89mvO?A7lv7glhpFpHhu`otN!#}`#D2DL0HSVBS|Q0sltZICILm>|fNvI3CEFc;Ku zdd}q^3MT^7*(aXTitKGPD(4Ai8BeG18jj%%bqtG*&qd-(0W&Hz7+EWl?!bpqnluEM zf=@s7-jGs z4tkJdZaJ=UZfya3KF;?5)9`=M<_om9|3I6UXcNmeKdcqLH;gR+O2cNczIg0y{bGe@ zdDrD?G^IEbkbMvf;GXRt6FQi%ClOD%Cr?X+6QV^)k2xCoZRMQl+)yNQks_8h{u?b ziDH_#gyEd(oWQNpIyR^CC87HkI0Wrn$I2CF3|ClT)3BnoxAOMqNc4 k-yYy4@JXX7mPvjMc`=2GS(!~P`-+R=cYnWQXPQBYA5`ytlmGw# literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/cdesc-NestedParamsEncoder.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/cdesc-NestedParamsEncoder.ri new file mode 100644 index 0000000000000000000000000000000000000000..628aa03f8a871a1a1546a0774059e41a396b1744 GIT binary patch literal 619 zcmaKp%}c~E5XJW(ZTF+=K~O;u?OC+v$)%!Q=wU@%_mo3P(^(C+O-WKe{(F;DK|#C( zGI@FP<~MuM7LFcnB?q{Zs%6bu)4AVqY5C%S4DEZvc;Nx z*l&MmNU%yJoQ%F}re1~~z&06L>`VmntY^w-8b}gGB%%|TWjoPek(@T7y4sD_S60MY zG^q5Yssa)`LYm1|nDQA}ExIRN?v!jx!>R^LxhuKsjP=)Lg^hem$uuRilul@{g@ZB5 zjqJ2xouT_;QY6cKb8~&4mk+r$w=-S*Hxs}wb((%>C(|speX=+U`5z=*fRKhoGUE-? z+KoXY8p6CEszz`+b#L<;9o#X-{|vkw{Vtq5I~xm{v)=z73-Qq5uM#YKB@J@BP8SFk zy%Mj?pt}@FEIb$P9DF>oa1SK*=hB{@;@3hgMT74KU}OD+>}Vt=KX7>JK^7Ou;tQw` GdiV)ou(g>0 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/decode-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/decode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..8484c88b1c58647e1a06f6618a3e27dfd215986b GIT binary patch literal 279 zcmZusJxjze7`{Q`VI2krtxzmf)c8Riz#nM}8_*G*X%)MStWJJe0Nt!0o#&HzV@3C&xEJ|2dPBmn$r_pCla zF;2=^P4KYfwlaK8BS0>hJPv6MMK#KhVz+{us<#fC^3hqf>z9gMCZ)%OAwCDi_Ur__ zB5#v8qcnE-jG_Avx6ofMrHPmzqq)_PKsaYD$FN+I}!Gl97>EuC3)^j2%=^06;gN{0zUd6>%jEt>NF`HG2~UqDsl3lIM+&t~1P P=bZ-%PTH3AWRd>>>#tmY literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/escape-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/escape-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..f18bee7207e63ccf33b47f64916ed5429689322d GIT binary patch literal 275 zcmZvWJ8Q!*6ooSs$JA?}g+d2U&C+PTSzKrg9vn(ZCJ#c7>qJ!2HIhupzpsirc08Qd zcUPWa^Z8B+;LYE9Ojpvw#;m)#!l=ZA1r&$2tGBHPLW>)~5o1FAk)?|VuSjD6_{;8# z_5{^5OKTLt)3V!(@HI~W`DAwJQwdcwiIC#3g8ODP7Q6b{8o3*ni(NK_!-OHe23hQj z6R?JyN&JdJ8-Iy>4CHtc(jupkEAlDtMlR9PH)CvAb#?g?x4+${%Jh%_Kxea64-4Xv Lf)lnUJzHcy3L#o= literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/unescape-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/NestedParamsEncoder/unescape-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..1e3f928a0060a2656d474a7e06a146a09d47c5d8 GIT binary patch literal 279 zcmZvWy-UO}7{+gqS}eC6CYWO)>$K~58wpDv;Ja4?cm|$PW1_ritc<$`S$k?^ xL}j(4T9)MEfCj0wr9aMjF%fLOx$A!Wd}rxdu*HAkv#)#|tA5BgXg@86z#lrLOpyQp literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/attribute_options-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/attribute_options-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..e68021b97f2345c67c3a8df8a93f53be2b0c0835 GIT binary patch literal 314 zcmZXPF;BxV5QQ0#TPQG9UCNZHEY$O52?8Q{C?Hg(4Awbu8Vko4*^W^EJ%)5atWWRm z``-Ed1D5YkR0BM?<4(tpnrdlgB3ogM-l#EZNkcT`0t5D3ifmJ&#|Do8uTu{2znZgh z4~t<`*3<;+iLgWeISv2`H}=}aIV_3+eGC;Nxc%FCOOS)dp=0?)#YA>3T-4s7WjWi! zWzia|MYgs^ZQIFbd(yo3>bJuS>P?iL#>Tiqkgca)MpQNpYGqC7pNl~%ZRv}1UY&_- dwz>N`EpF1xtJAs^l=W(odm-PWeY6+?{|2m-X5s(< literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/cdesc-Options.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/cdesc-Options.ri new file mode 100644 index 0000000000000000000000000000000000000000..58ae3cf51816d67855a699ac428dca815c1adeca GIT binary patch literal 1087 zcmaJ>QE$^Q5Z(hyvnK5jhz&G^On<=EXXk-RgNiOS9n_kHJcUWE7b{KsdNQ~FKmlFJ*(jY(gNa5anXYAaM_0vdc-u4ZqRT=NY- zP}<>1fN-?7y2)*j1V0tMJW}0q{m|5uB5zYdWkVV*YObwG1C@-zB*cIE{(0_qWZ!9C z7XcoRRUTlSg)$CG=?0S2&cCC(%uXN^f<_lE{%L?Edq&3X(GRrdwOl=u9 zv}n$-45WITC*ye%&C?VA8#xPOuir7HXo*I3lSz@M6L)sbt<@rHEK;>&_T&7I9ACBt zn->hUR+@G6%f$zGcIxC|w>F%LssJr4YOaKUOe5tXsL$^p~;B$7CN=MF~cua3bF3-}Ww?$rh)SXa~8 z1D@k@bm7E>>;VovbmpNwm(8Fog0i-UPkq+dkFbv?1vidokaFfA&ocmHw1I2qHoa5y zyy_Ig!RW>%=-p6=k3aV17v@lAO1kTC{h5IQcWf0y6$8UjQ*UsleSP$=!l?%gUSyY) zOxzVDQ@@kJefK_Z+~)qal&;YaKJhdZC-e4Yp0s-$EMDO!pnda>FTWUmCvMfIk?^1GFWHFX)GLHWIICr_n3x-_3pjz zy?4I+g!TI~DS$_J-09d;+pNu^&R5E6^bFWbRp*-uJ+^oRcpIZ37jEZo!Kw36WoN8T;nv7) zHy7B_od4kENyAGTOccGw*0@6uou@%WlvWGsgd!JHfgq%|^vyYM&gy(|cmHcGuhOo| Uzd7kpsq4AgEBOKKlf@AD50ejD8UO$Q literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/delete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/delete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d507a6679a5b630978728092498038923f49698a GIT binary patch literal 292 zcmY+9F;BxV5Jnl0DGg$(SlTHpuu#vJB?z#Tp->^1GFW!vG*%s-WjjLo_n4*&>)m(n z-gmk9hSldQHUQ6d+Ns!MTd(w0m1nIoDk=ixjaB)E2`^eP0erZq(T4l;x*&`}=0<6B zgRq`aJK>L`14!I)P&O_gE1mE$)C6JkKeJEZgBPwR#dS^6-~EY23i1WZveQOY`Pyi? z?Ph~5&H_(fo-(w=K}X&z(Q11Lyz@BlD5OywJKms;Ng!~k4E|6`>x(L1J{;Bb_;+32 XrfxUqN@>8FyV>p?{UFSX5h2iDrQKaX literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/each-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/each-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..67370414000b58eb07ab657878c9fc690f0e0a5b GIT binary patch literal 308 zcmY+9F;BxV6oeU&+Y-c7b)XE$EJZ>z^Xn1>MDkFm5KI}Ym&9qTI)0Ju2<6`s5*D_T z?)2T=`TPr(A1_n@JlTG)LQQ41)HA^s3X7TndrbwuPSIhBJ-~Y#G+BQ)nmd-J5Vc)y zbV0D5Fne^Tt_2vFU88K6LzJ}Wg3lPi&Hv0{z#bj8HQOyRCU|rhS!~BX;UcNDQG&0H z&bQUnzon`E(dA<%PN>mA)(T5)k6u=e8W}J*N>U{YvSAqDWv&c;$Fbn6K+^Zk!>w1g m+?-T@|BK1a1fOk2nOqHTFaJ&sURtcC#c$*qG|vXTkADC&xnV;9 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/each_key-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/each_key-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e7aa075fd11f29e185aaebb5fcb4165f821ad24b GIT binary patch literal 302 zcmY+9F;BxV5Jnl08wfB}EJX}vfrVziEI~jd4}}WBl)<_rPGi-{MYbc9e~;TBB(~G( z)6;vW(HAT~UZ?_i>ZgtJE!D+RF9g3-ShaGmCI;*^7yLFyi#1LF?}OLWySu+Z%JLlI zVJwZV2v#$0gLXd-0D(Prs`nAZ*?`u&f)U*O-)sYVXK`p*dR8#O%FuU`2p%1>0=zg8 ed~yG9IJ2wJc=4MS9(i>=JHCUEHv!baPjm#w2-2CR&d)XJJ{hyh+!%FtJu3ci@GMSXcB e`0VEP$C97LpQpd~;!xBVQ{^+c9?gS6@6&HKG-53P literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/empty%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/empty%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..56658941d9b13974f989432992130fd9a3c2b4ce GIT binary patch literal 289 zcmY+9F;BxV5Jnl0TL@yRSlTHpu+Yqxfgr$AhC+p4%3#@v(^%L(%XWnF?=ejm*1PZC zz3+Va1*?x2YyqC^w3Bhbu34!?ooCXxI6V>|ue8oLlzZOs3EnC+HwCqI)KC-jkIwIS>?Eop&Misr1&7kBr6r`2^T Wc6I8L2DH7I)!xt>uAemzq4))Kq+99$ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/fetch-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/fetch-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..946729f021460d36e0cd0368dff6da93bb64f2a3 GIT binary patch literal 297 zcmY+9F-yci5QQydJue~%hs{|?Y*fTcJ!v9pAjRn+TBTTKlig&wO(yJako-%?$!^hpsfmGo81fW78Lyw1^LjT6B8;5GH`X8xuu&mkH{ zVRS{Xok^!5QP~kgBnJ}!j_3H#q+TQwT+YkDpfFLux!UB7LG4EJF58i1f^To(|hmx z?qzX-)z2qtfJ3++O=_{JS8iVAYip8jg&{%`+RGRju&=Vpx1}W6$UDGypB#n=@ISg| zoIbo!Z%nu)_)PPKxc>8F+!6 zOQJQhap4+;CG13!${T@JXbfo_jY1iZznt@WR^{{U+p}6^qxkaAcRZAOJt>`#I_W>2 G@9_tTSy)v7 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/from-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/from-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..4c6da417cd6d31d2f5f6e72083a3a88b6e8bc7f4 GIT binary patch literal 291 zcmY+9Jx{|h6h#@3X-UOYv6LwjEY$PM5(GrbP^eIuGFUH((^xoumhFK0?{O0r*7tGl zxtEJiSbw}w1Mp-{I~jUvtF^i+(`DyqV8C9BGTjvDu*DO=yA6tr2bi`QD-Mv@vDT^~ z*vy;Tt!r?iaWTGiWb z7TD69|LE%JhUYY>AbN?dGDk1YRw7`nrJznUWI`11qL!L|IOo+xnXc}?QIGQB{GZ>% Wa;v{iaZoh3v)>!J0rj&+@A)q&+g$Vj literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/has_key%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/has_key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c158a314bceed9539fbb44f6da381770f59aaa31 GIT binary patch literal 252 zcmX}mF;BxV5QgCn$gLXKDwawNVJQpsd>se^EM+K26-*hdbK*2s9baTSLizU?1+kvK zd-PtdzF>2Dr5fPbO-CI&YO0M{mibMGL0=oLG#Pv8ahCdy7@ zW868&)>AJdDyt>6vL+W38l=*ezB%XBqRiL3)cf%JU1X{F`Y$vcM14C~y_4_JzE})_ F{{XTUQDp!C literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/has_value%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/has_value%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..24507663b4dd7984d8a421c1f8f03212ce01f707 GIT binary patch literal 258 zcmYk$F;BxV5QgCn$W%=wma0n^6c$*h=j+fQsHF@oQdOo5);V#Ah2x8Cr>Os)&@ix` zzI*iEOg~_8e4`TJ#a;F~HdGZ0bDO7k4F-8e+v_a@wi9`JFVJI!7l8LJ8gk*`-(VjFe>o>6O} zY&2HJeFj;3YGp)awWL~>7%Bpz0DIb3d$OuBfP-&-nbA;Wnfb?Ok3G_^0Lc}tQa_wDUb!S&(K zkLP0j37d~svH;KFba1(+w%OpNCnq9ZZJ6hnUXxN_BAW9lAtKR7r z!&g#Wq(NnEyi?REOCir_QpS1u5kfR8$!{OhWUSXIJ)ViOs3pJt`#TSny<4umQyjE^ HIfvpG#J!I#EGuj|BsJ(YrAl^C$WJ-~}khFrY<`{%4IVc`d5 zO--<#U|S5Ig9jMNL$6($!=msQQmh!k<^Rm(!?wLZ5_Q7I|**9<mUSvB$`S&#m3|;R| z-`!mX->~|8!vf%?9k$ZdSY|7Al}59p9G(e~_au#O6JbOt27r&wDQxZiXfl!{5O#g8 zRe`XcFk4}ceFxx~eIr{JKp1zzIGYiKyYtN6V-H4jHDR-iq*1sZS%i@v*g8MJ@?2{Cp_FDM^T)1hVfp`l qWI^D&FIX5a*@C9g{J~p~zw~(NpD+Fndm$-qru92CjnJ=JSW8bW4PsgV literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/keys-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/keys-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..579df8af27c659c374d6e1cb7020eaba6c0c2ad3 GIT binary patch literal 285 zcmY+9F;BxV6oeU&+Y-c7F;FJ6z(O;>EJ1)J4~42KQwGaUoW`o-7uk+b{yiaKVSVrJ zySvNf7pxC&SOUDbVW(q*Rk1b;PFH6=1OnupaeBw3mz5jCb%!Ff#jAySRiT@1&2RAPD#WHTw~J^0I44wkimx$$nyyj2z)AuZ`85Zmdz; zdd}bC9RKXqq)BsZO%#omm2syaYLBgmQdupq7A3kk76?LVi{ELQ78jf@9-n@#`OP@% V`fts6VCC&x?E`%)?W>g`q(A7wT7m!o literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/memoized-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/memoized-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..87e8f75219d3629f95d13de656e7898283439256 GIT binary patch literal 253 zcmX}mF;BxV5QgCn$W%?cRV*ElGQmPUUzZ>tQig(r%9O!6Cl_kf_C>ZM6n;HHL9D0m z9=%t~57@pxa|7_`$0MaPxAoRsSNX<~WAja|0P#{*`E7{-TO0x2`efKgfd9oolqbmg zL0i)>>}KzX;WG396FxZdX$e`;V@R=Hz^dqsr7GW9qxanm?|F6~f))pH0$H##Nu3E> z<3FS70y~vZTT^urH}yr zEAK>kf~+63vkk#!q8u<@h8|!<4&DS_LRRz`In^_`DLU&+m2aHY+iqfPX+k_jEq3Ar zvLJ6+oej1&d?wXJ@`_PAqo`921s+e6(#Fx3l(L>x`QrZJcUokl`t6_b7?jQ3r1VD7 KqkDFklKcU5rCLb< literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/merge%21-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/merge%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..aa2b920b2a3f404d8a3abcfcb82886fdd3280a78 GIT binary patch literal 248 zcmXZWF>k^!5Qbrf%0;9j>OvR7(k{jGv7{vW-}nw!Tm&zufty=1_4qRd|e25j&KaO{#HA6NHz!-RmW>yU~qeB>2;CS^W*CH3?6|6OE5@6$bVIEeartU6F|Xg@8+$o~NI C*H3Q% literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/merge-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/merge-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1fed74ae172a64cd4471be73403986b21e48d268 GIT binary patch literal 292 zcmY+9F;BxV5QQ0#DNV&xv6Lw+u+YqxB?z#Tp`}7FWw6ePlUUff$aX;e_n3x-_3pjz zy?4I&fc4um)c}vfai>C0O|{k+WxBM=b&3Id;bpqv=&->f!0Q+^4gPli=8SVl#z`7o z6KrPC4&CQ80z~R$)esht6eGIeD@JhhUvr4u&f(az{IX(YnjB6nma}(Q7Ogfah8r!n z?Ob3>bN+*qCrwt6)j{+M8$EPhw2rI@D2)=-ikgNH3wR-wq3v|ilt1R%0e?=mLMRKhXSg~l)*YDPGi;aMUEqse~%#@V7+_Z zuk+a_EO#$d0zA2Kt3yLou{0Ng-%=M0xn9=f8L-z}aGs;b3P*tV=?Cx^N?E>#MK>sG zN`lqoxjOR9pU3VXLXS=Vc8YJ%;AIID2$JAjebJM?J@S<$JGVl{)iqBR!Fd~1!~w-aGc6W}Rmc3>aC z3vwpOE2_r$OO$OOCzH|^CAG39pT^TDHCp=OoL93lU+f-#r$si3-~aiJfvDG$(klh0 J?8&Ma`42n6SrGsL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/to_hash-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/to_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0ea4e3859e89f2a7075f94ebf4a158a1309b49ed GIT binary patch literal 291 zcmY+9F;BxV5QQ0#TS&!Ju@siDz(O-$mLMRKheB1ADT8%RoW{b*S+*n8e~)QkV7+_q z)A!EjAF$lLPz~@j95*U-)Kp778(J5^7aPXpa)Qf=9C_$~LX$Vok3#kl!Wm#68@pN|o@KY_W X;pm-?j>q+g6T#x42p!eA~cSl^@ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/update-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/update-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3f5684125a350ed9f34cf93115699ce15f490cc5 GIT binary patch literal 322 zcmY+9F;BxV6oeU&2~E|hVrdt`0t@y0yaWM}G88HVQ-;V+oW$VdS+*n8e~;62VZPIM z-(5yuu>N?#3gBrt?xpXrF4pQQPvX(k+)D!FHOrH2#x1Y;5#Zf;g@e00$Bbkd#AXy) zRS26IwdeL{Gys7+_HytM#Hr!dyMiEW|91`n+*)or!mbMvb`K{OVdN7QX`{5vlZ{ql z*USbxoCO}OICW@>z4B!zd98-lm5s%|^jv6JVpCQ)_#og)AvOL|N()j<=Xz;dc^d#3 qvM3767c5R!Y)SKEagXBrVPdDN@O*hbJawy^+5HV|&-JtB&e1=e+hbAy literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/value%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/value%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..58f5f6f719d617d733b34f7fd94009738697c513 GIT binary patch literal 328 zcmY+9F;BxV5QQ0#2_z~@#nMh;frVy14+H^`G88HVQwHmjIE{sqi);tfe~(EjA=Z1R z@4fFd_<-fx6IB2Y{b4IzOLehSXL%fcp&sQu1NNNd@j63;H68$72dAjF*T zt;$U^FWAsL;LeoOPm)rnoMQcFRNsHk^-fEA_G^qnM0!3r;T*`gJH r2E>EFx1aDZUGON$A+>O literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Options/values_at-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Options/values_at-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e55bf7116858b8c05d57b1268c9c930b2a221bea GIT binary patch literal 300 zcmY+9F;BxV5Jnl0DWvLDu@ng@EWkiLUzQ*sl7~WtV9H=!5~s21_#)c@<=;0nNQm|H z?&*D}vrkyQKT`?tXormo4ORJ4pNV+!g{D_tVqm~tG7(>A=&-^8;H?XqtiSmq5|(8U zb$wxUNwAuP8+7}=0~qant8AD-ly>NX&l$nhe`Y(ncMiLTCFeO4akM?USi(NwBCWMi zB3>C?tm`RaO;f{zD~=3LsntO?3M*}QUe=CU8L%))QY}leVGQuHP=>xa=lO|<=ePHJ eHTb)q|8y}9od50`4_SFR^}Uj7(L5RSo*w{GY+#1~ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ParsingError/cdesc-ParsingError.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ParsingError/cdesc-ParsingError.ri new file mode 100644 index 0000000000000000000000000000000000000000..a820abc9faaa7208d7307a3c779c53e7a7f57b5c GIT binary patch literal 418 zcmY+BOH0Hs6otExGBXb4PIs>>Yta%Qt96myu7wq~_y+g~842v> zmo1G}oj=S4gm8DT*a-VR^Z>zcXu}N(le`z!J5G?rlu;f*k~i9@pk{QnXbx@*HAc9% z6=CEBvK(9O%Qq$Jkj|Bj#kTaKGOEO;l-T(o?aE3S{LI*S#*&Oj`xEoHNE11(I4W_< zW0>?qWwZ=DhIwz%E9q6eZ>PQ0AHu7#DbktloEM!`r%^T;0h{jYEYygT-D%b37~{(W jJO@3E9j7|VPD>s`k$hgH)8nfJ)wR6-`xP6k2cv!fuflx! literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ProxyOptions/cdesc-ProxyOptions.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ProxyOptions/cdesc-ProxyOptions.ri new file mode 100644 index 0000000000000000000000000000000000000000..22d3a9bb4ccd6abc99e55ca3a97e8c7f4b4d32ce GIT binary patch literal 514 zcmaJ;%}c{D6yHJ8?h{2&*e=r31lf9ixfG^@9;Tx1ltW3|RD)SxNmIN1_a^&5y-47N z@O$}vym#iW;p*icGk{0b8?F|L*EPG8ejHppYuxUhDkHJ136O_n9E_J-^PKMh{(zKN zY~9ydg{uiYu-^n+m|nHycqJANoiN`X z9q2`cR3Z*0N~ZJTAU?-~r^uCxymMVtA@Vf<=;HX)Jl2q(WgE z(r!q5A?xgq$GkY`WiGR0Vm|YrUp1+c86ytsIxY*@c>g%CzebftBQhg$OYFg*((;QN z;T~}?lx1yrnTeAK?K^-D_H}40VRqo>OVlmbxpVG1PeY*HXkzAiyPBo76I!j!=}Cl0l6e39({`S+w`VST#y z-8);p!}{%!YJht`9!xq?Q?2c}!DbjY=Cw-$ICLA^Ga|3*BJuPW?P9CBOPVc1nx-dLH*op+ooJ HFh=nUpcPaR literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/%3d%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/%3d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5528cd4b6a33d396148cbdcf80509fd29f73afb4 GIT binary patch literal 255 zcmYk$J!``-6ougo!3lMT453Rp6m@BrM)NHJ_sgIm9YQ*J5LdDsi^#r4k}3K3Rq)dJ za30?I@(0$3PtpKy{bg@rOLeuj3&9qKp#UjgPWqU&ItD4tlBn{y7dW_YEoakO6n1KL7k1V zHCWsJ6lCM6lM$6Ok{YS0k4X+v8ArdI^J*s8?Gwe;_~+}t$V2jAeMGO=~5Q(e7mGAM9KgIDpQ24>yH!*CpWSkQT~06vUEN= zkKU)r3FgNwNq~>`zSrSGs+yZ|nT@M+0?Do@vzG!LD!c<6QC>fLW0iKVaehyV0@AJ* z)<}Zqf!U+G_8mYp`$o560%_i%3%(k`G_Q@-Wwx|NZ0bSXxQKEwsB0&p`VB0n#sq%R zs7(9gdF`m-0fp6^YA&e_QTAMDOE< zl6n_qXVJLfC&-qmml2h>l3J;0h)E7oSx>)0h-Oh2R}U0B%a7;(GOyC%zx14`ujjZg L;vW5*#}LFHh1XL( literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/build-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/build-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6835edf4b012309862ccafb773133a4e3f20e9bb GIT binary patch literal 264 zcmXYsJ#WG=5QZ5lg9sz)(xpllx)jgHl73mu00U~L4A%K0#lo>I+fl{8uW7p8-TS=H z-7LOfeSGs0;MraFI-k7i)@I(;OEDU&2#|Ny)*FTq6}3igC~`FQ94y#+#>6%S!%W=B!_l!5Y zQV~cfQlgo>c{A_LoWzgp_3F+@#=aWYi|)1)!%)6baX}Yfgl;-;gptq7g3_gMq7lCs zTM4=SG^(xv$Ji0X31a5o>K`CI;pD-vw-fKZaNE%`hE2vEw2#?5x5D|MB!)*ZkMYai z{fYgKt)85)8-l;1f_|utb7luk+B(yxAEj5%upX^7&LcBe&<$v*V8H311&0Bo@6#|y zL9>82`c4g2c)4NhUNtCeCmgIjYI&Im6)eeH)j>hiPSw}#B>UPSvZ^Q9SFYXzv)uH` zR~rzG(oaJbrmMWDJE%-sNuxaq9;zBTv&(pr@p)E~GAZb(7ClVUk=34RZpXS)5>5PH z*K&qW6l_Uk*j6Yn(I&n?Zp_9Sb|II)DI<1no$OzFW3wCV-L zY4{P{+#DIO%U(3b%fN_tfmL?e@*$IK4|D8eeiqpIIlgBlc|6|1ZE)i!u4|38xQ;Sb Yv+QsIv!gfpML{qBb!efz{QFXW1D_w#n*aa+ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/inspect-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/inspect-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8deb6a0b6edabbd7e550c650ad38ccaf3ad0db17 GIT binary patch literal 265 zcmXwzJ8!};6ona(K@B77!cwJ6=>VQDOZu{!0R~j24A%7{#lo>8+fl{8ud9^x=$!L? z)A!C0jOz$ZFob$Gm$ zcZ4x0`axJDJ*>v(J%-EB17yt5X_w|uR6T|in+e=it+Bc;AFL7Ec4TZrMsP7QHbIab z`2t$`&Ln=;sEqrLybZqN35C_%w_JLc@^j=uTmM5TZ6rOL$piXom`>4A%7{)QV$Awj%n4-1jq+#>n+283NHXBl*8+6tkMDC6P>a;JeKI5 zFb35$3u~l@`?7k#Fw7G`M$DsjX$4g?VMwuCz`E&;)ouM?jo9^tunQT$MIk%~LH6Ve zXyZqd_*tVe?kDm-_>m_RR&(ET>0Qdpkqd48FQv3wwDofPbged3w!i)N%m*g#ir3MH K5$)UcNBRfK;#5`u literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/name-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/Handler/name-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fac10d3f62901b35da38d9c9bdaf9cc5e629bea4 GIT binary patch literal 270 zcmaLRJx{|h6op|1WCdEOOe`$O3~V&>?GnBsJiri@se^UxIAHbKj;iI$j4~}m=jZQu~e{XM&yzYXK>jJo}7}m7gonF!vNm(^&tG&@OC9{>pa!sl0fp^)cIqD7CBx4j>!6tNh&TZz#cVMafz32 zN!36$PE<)|U_FxuwEZ*!1b-TY_92OM}`# zQJO(|au&#?J~`4^GZ2qd31T|JjP^lxgbHOYMNzbiI$uBa3Y~k|Y|);=c%aI#{yB1G XR@M3Pzj|!V?&q#Q#tx`H<6rRyjnrA{ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/StackLocked/cdesc-StackLocked.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/StackLocked/cdesc-StackLocked.ri new file mode 100644 index 0000000000000000000000000000000000000000..4c0d921c298ad98f7f0e0c1003e752f16cd7fd3c GIT binary patch literal 544 zcmZuv&r8EF6y8D7vR^m^LG%!N@aTF@FU7e@K}DuJ_0Xkhx`w4qc}<=B?@hW56eaM& z73CVp_H(ue3`BVNF3dF;ao!2Cliu z&2R3TX}SSg7s$eq_tcfeKt;ndyeoKxHS9&T!CK)`Wg_2WU2xo3{g~#O17=i8%UDa} z=XPy1k$#v9$s-R-kxui2vniN2NqTU04{1mALsbf$6r5(JMw8^A%0$yt@-@c?{t9$BheM|h;hQwQ3r+hiNs9EpH&O)G z$K%6$C(AEb?cYcNJonR1ha=V1%AA(jIo3D??HI6kUS>BOT}&o`J*xI)G`806_OG*L zoI^5<(i%l@J%c-R?Kl8Lee84}mXH(!y5Oq?oE43+y3A5*EvONS`VeI=q_*^(=Xtd#v#a}7PwVs%-NCQZJ84O^55HKE X#3L8~_Q#N`%X#ewxeo2CMep+;yTDp5 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/app-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/app-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..eefcdfc1f0ca5f083324627488806b6050724de7 GIT binary patch literal 653 zcmZWnO>fjN5bXh_%T_`hDmXx;QMiDF+MK-$S?AV}7h}>4=x<)!1`3pkRl5xkPD0U}xe)|4HS}kAm4ZZy9ba+_FSMwo! Mb$&qe$zTY@FIo52tN;K2 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/assert_index-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/assert_index-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e8001b9479455159f732fad668e66eea4d2d8aff GIT binary patch literal 276 zcmY+9zfZ$35QRG+Q_&6}RV*whNC+0{`MQK(mNJx~YNrg=Id-U3$Bxbp(ElDo7FbX3 zzVE%0=?)f~m(Tz_`s3Q9ebDv7o>s*L#%L%>>$Uk}z+OdF+zKSrcm&vBb9fr8(}r&T z1y@W6nD=BqFqr^XBYTZ>7NkYT1s0C1t);qu_xQ zTd^(hGITb{y+LjLdz3AOP9{{&$k56r_>{>}D&xW@=e(X&#r*EK{{7E?Im-*q{}j(h R(OixN-vV{$o?YI;zX21*TPFYj literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7f6160dc2d080d18a8c32c6641a1c038683d0410 GIT binary patch literal 278 zcmYk%Jx{|h5C-55D3oSFqGDknau--==Btpxm!%A4sLGVVIwv-@>f|EZ5vmaX9fvHe z@7+DR_iX+F%iSy008ia%tHObrYH7|(wvdCdO#;aqFWD_ehYg+pc32;u$BA;QX=9Uc z4rxC~Yifd<3EQGO4n07WhgNlA4r$S&3%;7cqR_^wl4aJ&wVvR$i>~+sm3we9*(7_& z3u;Xe2ZfF4KE2S6S`koMB}j{!x)5bAq_Xst=Ow%F%Ifj5nw9M8j{0Dz^Vwte{c}IY ZMH;JI{%a6JUSCfizmsdxzF71={{?CQS)%{| literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build_env-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build_env-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a5eb6c4d1bb3c2efebb3b95327985e5d20827b55 GIT binary patch literal 1244 zcma)6NpI9J6y|`^4OJW}4#43tl~AiT?MR3N9)t#Hheps+b-T6~t zKQp{4g3-!!ohmpyxq_cKw-Ahii)iqPl}&vR0tY)U6D`F*%)sEE8m)uwc8kr>?EKT71VUNIRf>>n(>SEHF(lSI^|TL+aIUtV+5JK|y0|zcpslpBNInf9)fskPKUmjc zTp*{J6FY>0+X8gnl8?G`DwGPh-k3gprxp!0(FuJaq1NS2iQMlC^#-}on8HHYpoQfPG|+f(omqsL%C?@bKee;dvjfRl5NIEbI--B_S0@eyXNTQYteu)`bJ&5cDNzv3e~=$@j!nODTlsts?H*LWp=fV*GJ~TagPgW zB~PL4u*&GaK3mOi(NlZeb=G;j2cY1H1^Be#p0`_~Bz3qQkE7k)iMF_IoBl@e67PX4 zZtbl$84*Hw0Pb%ZFnckkgqGY5^@t8urh)%kSu3Bgi}UkeeVlEx47NJXg~Vt8QY8C% z`#S6!dK}{BRY0?65PfOhr{W!Xz+TA kj=M1J_P*O*ZTyZNqnG#IAUd3+uiCfd#CIpZOB%=UKQ-%+5dZ)H literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build_response-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/build_response-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d07221e1cf83fbb6c7626f1287a8258fcc7c3993 GIT binary patch literal 584 zcmZXR&r8EF6vuavI=6#@V}g2!6?B4bJ!hA>X`$f8D0=Flr0v@pmL@ex8T;=|f3QtG zg*?7|-{*b5C+#oX^WQ{_@hjiWL8l@Kdi2z@FQbC8B$S|X!4+88dUrj0;1Wp^vcuRX z@n%{|K;Hk6jxE>4-MokxjRn4`?dL>piX3CJtH^-sHttSxBDD%S0^k1DEX|U&BzbC$ z&jQ1;SV|FtQlJn)K71FTG@@LK>RSV%Xoqs56y<9~HPWdR#X2=FRjA>7RLB}zpPt>% zXp%745(!9YbI7oq|HGIv!Z#n3LraW14a!3-IEPqM!O;uar!hNB>lLS6OmCJra%%C zg$h?vWT7SzgHWtOL$6KvDvW@Mt>ZXB%d@WshohcR1O8MoUYX7>j;c08H}2PMEriSn Jn=uo*^8+z8zViS8 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/cdesc-RackBuilder.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/cdesc-RackBuilder.ri new file mode 100644 index 0000000000000000000000000000000000000000..2f0dc02deb6a29704adb1fae8d423797f02768cd GIT binary patch literal 1341 zcmah}-*3|}5bgs?vvxlj0wxeL;bGfLTV5Rvx{XalVt@*RhX_SZa$U__JJ`;;O8etE zH`&s$2im9m&i?MZyU%&#pVOzK4=SVdv(i&0js-I&-sXN3Y>rrVc~o+dgZ8L*avB9Y zr%bb)%_&{Zg&wB5U((-@SugayEBd0MJY)K@EGR|(athM=v^y-AwkGye*!Dv|_7#13 z|Lj++aG_Z-@i5(vg3%$VH4r;tmK0iLU+H ziwR*84@uC($%}%wQ=aDnW=sPy7P};S6JS?d%<-5hxQ5)ZxE}X=RY(7*JQ7S^e&P~Z z51Rb}I%Sqm+o*pf3Qq4vcC1iBX1S6*39~&~YC#U(k==>41?~4uX(qgvsp;-M$rZUt ztI6MVD$OT^)JU&xoDfHmfXq~mg2@|lS87y^hSGB_PO5xObJWn_A`6Q%Ayk4*oC@N8 zOEibo3G@cokC?AHe2}>lMOTMoXBs=8o#B`Zhyo&b+81&){awj@nTp0}2lw&nu zIWEW~W38r%WvPHfjgw4Ci#{<)3PQ~W;o2ZvAH-hViGsBWlejZ&s&TYOKNo!6qD%$P z(18Cd9k=k`c9!a7&gAZTj1~(wumGYyF2!NPS8IS8;$ zO7%Bpw#T;c#)0y6EC%es8J20v*ob(5XXslf1Rz(xfCQa{s-NI=DVO zeE6QNKVfrt4I1FdpZ1i8V7iSxZ|lmCqf89gn`rA>fe{U!01l{+&$D%g;@#h6$Ao}t znw7IUz|F$#F&^g$pxE!_&Cs%^i>+gM8iSHqf K=w2MA#D4%C9#%R4 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/dup-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/dup-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a794d850c49af42cf73fd17c13e3ddd8be4aa507 GIT binary patch literal 252 zcmYk$J8Q!*6o%mp!7=rcA#@3a;x5h7Xg*!so54dmgk~bq<4~)YI66D3`1eFaV(R|s zdB4l-6Yi?_U;$oJ;{CnPl)OD)-;m=dKx}IzWr>Up{s2^HkDJj`jXWDKU1gPZ=zV0XfC}1zZ=cC#U2Sd9!Ng#)_weHgn^J%^#W< zq4P-}95%lHj=JU0>4b)y4z0GKPm>(AaTHE@S==c3aPIPCm3BG*+6C^A-UwsNe*rfc BRk{EG literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3c2dc970f4ddc414f5a779d2f13bf9db1c05be83 GIT binary patch literal 409 zcmY+A%}c~E5XC)6tX3A0#fu(71yNbto~H=)tI)%WEPCo8q;0wln`TOqs{7xY-Fnd5 z@aFO6H*Y`qfa&rXD}V>RSqRr+T}1@Ri|xOOnHaxh6Rtn@rtJ7>Pc~H;~$PIgVO*2 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert_after-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert_after-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2fa01c7aabab6536872c20db8a6293e581621981 GIT binary patch literal 290 zcmY+IAOq>6{4qn>z z@%Y`ni}@EU_HSMSJiF6Q$D>#E!dzDQjd4L!s2e0gu2(m(6$5$O=t*-BV1 c+lMn(q~o6JKQqR#l(*BrAD%k2uNFgKzZL*rQvd(} literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert_before-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/insert_before-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1f33a9733579800be07ec1f9c826cb52dff51ca8 GIT binary patch literal 292 zcmY+9J8Q!*6ooSsH`Gfhp-UFyLSKZ&^UdPE3?9-Uq>~46CCiDhtZS}h+Wh;vcxl(e z;rq@xn}5P$_eKif*`2mJ9I37r=DbX=jPsg+o1;-O+%+$m_wZR$iY`LxX2r0b(tpC$aOOb);#isoCHrS zqfNAjET_%{anx8FckrTN>O??kwV*~Qa$zLl>+@trpGHOZIg!IZ%|zl2(Ga*^!__1j|g|wLP*fv^6q^N{SFQ85E^oY3n|7u*A*}s@d|K6dH$HRX_W_9g4d*~AsZ)Q zv~=*WN_+I@X#|+rX;3z%kd-6)7@7^-mYp_=k-})P>sEK?XO@fAeeq&eYoMhYbmYCl zR@>jeJMRV_Q5eNt$ECAzmID{cxC^DU*)Wnn^=Mn8d??S_@dvfy(6|AcfLyFA;E-UN2smnX>+O3_9ZODXdXX7!n zY{%Y#SJb;CPX@IcKBKgOdYQ2GMv|3^hLk@?*&0vZobzT;m&=FE?`gHp{nvl8^H8Xp Ox$QuqNB`n6M*ah84qGGu literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1eb68d38e0037030cff48bc0ad26ef2578ec13a1 GIT binary patch literal 278 zcmYk%ze~eF90l+Wau(CUp$OsT^a6r+%1f^?fSAU%? zp%juKaIJ)an+e>bZNmT%_0Y-Q&mk!WwBA)SxF{N>WtpW~@l7+)8yjWDC;G{9vLzpo z7p7C5og~((KRVV}(=m@+OJ*7-Oz)%Y7?;|7=XqYu%Ix~SmE$^nM0<4W^p0yI+J|4P YNaB&pfBR!d#nrU--PjKGt48PY9|RLxegFUf literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/response-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/response-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8faa188fb7f025f316f5b6658b040a90e5c22506 GIT binary patch literal 280 zcmYk%&r8EF90l+lBo2$hMk);H4Y)CZ4D&SN6Q%m)?Y)x?mWvohUdL=&`~P;DEY$9jvR2zxyj~ znGlflgK}0A+|J}4eKYg`lRvbki%UrI9(@eu0xt5}I#ck}S+%KWd*dfss@Z<_if!2^ zWI44q%9Fv$cE=!VPpyoooRL&ZOAiBKo5x=) YPo^hV{|-!{(AV?Y5ArR#H-{l)KioiDOaK4? literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/swap-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/swap-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..719b7af6083c0642f71caf27d4fcd4873a05b692 GIT binary patch literal 274 zcmYk%J5R$f6b0Z8$P}_LR4kQH6eI+wqMmP;@UoPl3>8cntm{WwD^48Qj!OSMhAgZ{ zN1x6)n}5M#_vR$PbAQ_EcyOv-nDeT*2uByDJtdR7(7d($iZy~-ca@53s;6V}Q0;g>73 X^yBK^{1h^IJ?;H)zC-(JF$DSp6Bbyl literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/to_app-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/to_app-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1b3f4fb33f7ca6e29ef2f959e74baecde240958c GIT binary patch literal 267 zcmYk$Jx{|h6ougq$W&zMP_eL}u)sn+-!9?HQid{AWy)Y(I}Ww#_*%9j)PIkwFt8pS zJ$kQ}U$EZ4lLmP4=bgz%>bteQZtE(O#1I&;57E~50weZ#2H2xMy-wEkCO-UKwoC}9 z!lazl1a~vH!+4qkK(VLM_`HOw2^e$g7I4!H)|sL@t2Vl<=%P92i9QjFc KMEB+}CH@QaDpxuH literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/use-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/use-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..feea659fbe4a90acfad3bae48d2f86b144a7c97d GIT binary patch literal 272 zcmYk%J!``-5P;zf#WnTPA#@3a;6iCiX*6FK_sifR9YQ*J5GPqqgk_)62POZ$GF~#> zaNNUtSLrV-_g^Fd-iPx}`4ctuQeRhj8k|ZX`7W#czC?=+o&okKyN{qvqwK@9e@n^| zvM~swCBbTjc4)gW0z@_RYVav!#fa9sdI2{@tBtDiwb5eR&g|Akm5Z5uwIZqqUtN SsGrK^-Q4>_wny_h-Lii(epl51 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/use_symbol-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/RackBuilder/use_symbol-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4ff0f21e54246171779f8d79989111e9de471808 GIT binary patch literal 290 zcmYk%y=%iT5C!lI#SKlN9YU8vF>WYrF^%WT;(i%CBtvK?58`CWiLm4|lHB6|zA9d_ zJ|4fjcQ*fq<^F?efY)x^N`E9#E!BCMTn$b#HyTblg6Oj-lU0Eh1&#oFtlPIiX(8?X zNo^Aq1zh%4{h*fwx0Aa?+YUWII5HU7`8h1|9<6uP3@-9UX;~(*R(#z|{MrVc@ri%2 zJlaHGkmY2QXGe)bbqB{9ONM#mS~6-_O`Q+2V_a(b&9bbTmC4)FZ>E=bWDV+fjm~9%_CsF; literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/%5b%5d%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..842d65f5537c88bdc986bdc499365d45c41d0ac7 GIT binary patch literal 249 zcmXZWO-sW-5P;zxBnIO}D1!7N@uDDh&m%%a4dhS{r9A~%W|N6sy2-@-Q1b7a5YI0> zyl3$qmfLr(0A9OcL;k>Zxzy)H8kb)$5kwz(k>2EJvBm*lOFw~}znj`~l;@E2K^a{! ztY&0`_85AAQ4B40K87Ug(Rx=d;38|Zp(0%wt=7#&6`2z F#0lbkPi6oB literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/%5b%5d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6a329c187a8f5caedba4db307a2b14e44ede3bfd GIT binary patch literal 240 zcmXZWv1`IW6vuIg62&-5DY(U@E_(BGNogC%po8cXcPVWr!fleOhW xdQ^ra*Rtf+2h>SLhJS?+#UxMW?++R_&vzP!*2RC~v#)#|tB!0NG@k~Y6MrsMO=JezSPLu>1Dp-xzGDF&r$-lA^_khg**v_OY7jsR==ZX6tk0>2*Lwp2wh zuvmUvpL6{A?vM!_-d`I5aA)kC>nqKhh8-x9#rv17n;EMWlnA?}O2Jp`9Tvm=iKdrfS4GRnn2_>up zy>zOy%;Iycis5u+JG3j;A>Yn+VGFPR2uW(@%H=c3OI1BL`P71j8OynGs^ zq4*6LZ9^7jaZey`49^G)p=rx+d&;$6Mp%dE8AV_;O&K8W|;hfp{qP@YsWyy8HyvOF0 z#S*rIo3xQiO+sDzr##}Wio%20+XOc|_8a-miopRpZP;n(9R3oJK1 zy?5VL{0W=m8@B*2dODClaaV8Tb(zMRE)hiURhe%0XtBcy;7H#iIUnFLkXHVnm#hJ1 z_Bq;DkeIPivSqkmqzAO;(ExJKF?( z1$n`P^x{O=N&V$SZ+Q?N8%2V9(X#d-;Y34g$<+R=bP4$jvT6%Wk9e&^^y7VTH=Bg2vtU0Yj z`(j9~RYNQ-B`2yTOtsd%F{I>DZPM&G%?2qBwkO14kqnrhkypYI4k7OPQVNEV&&6Jp zYnODL{};@OjXSL@XO>saFN9&I#XGg!Uy5WTT4QO;_`y4ieIgrfGbF0IV2-3sw_FbWTTqMK&GCedq`~4Xfs_G^G2LB4JDF6Tf literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/BasicAuthentication/header-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/BasicAuthentication/header-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..55bb6cabad4e4a5b28daeb6833e84aae7d10646e GIT binary patch literal 311 zcmZwCJxjzu5P;z;Bp#-dLj)U1r66XpoNID^1X7&E5vvr->}GRW-0Z~tK>wg}ahNZk(&VMI2pm{M<#C`zezi6TW literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/cdesc-Options.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/cdesc-Options.ri new file mode 100644 index 0000000000000000000000000000000000000000..482b37daedbe77d7ab74776ec32b14ea50630d9d GIT binary patch literal 580 zcmb7CO-sZu6zoCT?k9-g#fwxBMcMZJaw)7Xc7daKK^0xoPk<$RYne6x zSZJf#nh8VQOMo7M{2zeb@l3GI1qfQR>r>$0Sf(z03y^TK6>>+_Yuf-=RULN-qqL#Q zXyQv0geW8)4AYWV3`bWL&*O3{ELK}x@t(SqHB-6ee}W{HH8swWH0RFOhaJ|V c6=;VpiXpYwH{ir>HG3--OX^Z)<= literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/instrumenter-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/instrumenter-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fdf231f9ac75eef15a34067c9f2ddbe120d88ead GIT binary patch literal 299 zcmY+9F;BxV5QRG+w<0V^6$@KfKuE;%l_3bQf6Ng$jzF<2-{r98|0x>=5 z^xl2%oh;s9xqYG<;KA?LChe%HmUb@lbL(RYLuY(4fdP9KGQSrXu)#gR)_e{oCII>C z!eq$tpq;G=E+^m`!^hAAjPxUB0a@8&NU@s1Y1vw5WPamwWwKIxZRns`cr>L}X^u;-^W-^~&-yEW4 YHjX>{X+9oAeKA$sQ0UM-I*gHj1BnG?DgXcg literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/name-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Instrumentation/Options/name-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1657d73e6c21569598056decd52bb5d3f24bc64f GIT binary patch literal 283 zcmY+9F;BxV5Jo#7w-CmPg)J-~q{ai&bqNA2WoVHqI%TlVi9;=HU$7ma{(I7fh3TYE zdV23J7JFFkUa0|i_Q#D*2Wso3nOFIxN2eLEH&NwJ0t2>q1lZ~CLB|A8`Iy4sv`?4} zd4Tu+bmQF_TQeab>jz~`LvT9@HWVc!3AVxk0Hf+23KWgtgiA$YgExqwjxZj z!u)rwf?{j-0lXw5B|6_=|Fu~+Vi%$(C8ck_AJ`!PGGHgdxRl1)FBD&SZeIsvZ_d9TrAy|03>#Vq5kK zyrI!1c`(>p{~qNKXp{++Gm-|W$)_w8r817bIp^J~tu{Btf8GAJny-&k15XCzn$NgMDfMCnOf+59?DSY~Ywdro(+d`nSx}RCzbM)rj<^bO-hBrT-rkqQuo@+Y^L>Rw>4L_y QuR4OCIQv=o#uS~Fp9YtpN@>Y6j9-!SlVJt3w{u;2%Wk@z>YDiUqT6&LKRR z>0E273UBc^^1|VV%Z7`YaSdmw;kOLFS*4^lfitoBkM~na#m!eP*pXbE z?77#BqSXw+@QMK{mj$FKcaTdBxD#oirI7X@*l;hO9w?ri|Du&D8P=li;NQqUm`+?h z)v-&{4~KDUwR1|yg)}_pX;UBuXcJ5|PuOJKB@FVm_VE-l3HO3l%m*}ecRnzYxqDnc z+}^uPo}1Hi0IN&*SbvL%d)#&h0YG7limPV6dqDfP4UCL2uqvghSrAdI6CZefJ=H5mo(bHM2sMi4m{K_Suje>?DNpFtNhwwn8Y^!Ao} zE?}LCoG#rwDr)BBWSR4lxpgdgGV8jTbtE(Xa3KSoG=I;Rvf?H#7|qf9fw*tcJK$N|2-~ISx@i% z^zLH$4x9b6lK_wQ*s6GNeYeq?wv&iyj#x|1GrPVrt(HoWAH>oc@nQWX+=x54Io%7^W?AS;$Uj?!|;S%##uG5qL{D!XccuT`2|gRft=yEN7Ni+v~X1;+b0R zFL`nyw)z?0L(v$Id|}9_l)d~nP10kgOmp`$IZWB(v(LUXd8Fp`{o7H&sbkz2;&P<5 zcd$cD_k~?{2MoIK(oyWrZ4$fPa7kGH$8FcW^D0z>BQZFd;x@S;i}Pf>OT$yK_s46z IQdKAUKd^S*bpQYW literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/create_multipart-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/create_multipart-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..508104767e375868977753a553f6ae3e5a698d1c GIT binary patch literal 299 zcmZY4Jxjzu5C-5YWIYUAA*YRvL<9vfYdhCO)P)qWIL<1?GD#-h;%+wXhjRb^as;oj z9cJEV-jn$UEZ48L0eJ3rC55eRtED9s29hS~payh-0ecfg`Xta{i#vcdeMj;E zp!{38`FFEoLO?RaTC2vw)g+bZzTyBdve8f<=8)tE!B;al%R8m1NN=^Ovu>g?H%Zy? zmq%B#725#Mtx-X430u{Fdf7Q^WWZXJw4H2hAI5kuYtr_Yb6(Ag^!$$cpNH$wL*wrc aDS0y1S{zG^Bhg$=pT1jXP`_yOp6>zntz@47 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/has_multipart%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/has_multipart%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1fa80df7903baa4e96e65bb7a281e0dc148f77c2 GIT binary patch literal 287 zcmZ9HF;BxV5QRG+Q#Dc-Di*dNB)SmK*MT6wQigP>V9H>f6Neb=T(BLX{(DkIbYOkD zci;CemhZ4Ryig7B)E`S7J8G(pxh&GF4uf=~jb=a}9~rP$QKXqbj}0CH4*Gl4Ap(?t zH@E*9J0=7q!>FvO32tUeiT-OG04C(g0nf>qC_9af=|6&OJvkXsSuLrRHT7|NAEeTjemLjVqDWWwq&~N&cAiXQ)@Su8 R67}_LxF_$>K3fcd{{pv9U&8l;FtEem?9!8;+B)FU?HMhHQ00_v@VDIM;7l*QIW^h(?N@JB?YbCO70%dmM zWafx@up(MT?~oT{lxJJyt?EA=>ns`OxzNa{W0HCw<{cBL={wK!W>%$-x0B3$GFa@? qPx6%XN{6H{s2cB}H*FgL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/process_request%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Multipart/process_request%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..195957f1f7cfbd89b367ae7210afe5c3b3ecdea2 GIT binary patch literal 291 zcmZXPJx{|h5I{R1Q#BG(VPOkGf`yp%IuHa{$`FPMrVN(tT&RUVfvm=Q=X2&D~yo`{Ky#79Rc#hn(~&3AbPO}*v<=pHk+hJ z5z@s!W7obwIaOd5n$40i!Lpps1JDT7O<)ZZLldXjh59gtE!)b%KnOO zf+QRA0<`v4C%!|`YxfrU5WM9{NQ2xDTzQwK^N~w5{)tU$7ma{(D@7iRtd0 z^xpUGVzGzi?v)h4vp;QhI#Aax?Yyb3C8{GCBMhoUp@8CzH`NozfE}IycKUnNF`btb zvi=y7B_Hqq*)|2|P!6MXRuSAzs4a%$H~?hs*lV8_P}T#66x$hG*2X&BRCmtGwV7z^ zFv0T7tW}W3ruYO_Q*VXOT(qm4sxExv41-zipAXR&{i^K_V1^g~s_ z!yDKKDh1bf6hyM%Ci!Ay#>J;jG9`<|kThqB%n~XATNs_BESIYwYzAQ~z>Ur0VmJ0% z)OO7}VGp~gT`tm`Q|#DW(|TF-e{jIJy;4cTs9`g(cTuNQd`S$mLF{+A(1r-g>Z`&w zZrMctxNr8l=)xvW_x;<8U{j4@FP+!Y!8rC=52jZ~VaKwB-Ob-S(|R5w+oLt?#2diF c)?kk}f_f6$jyX{;_OEvPalA&>pZ;CNUy8@i-v9sr literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/exceptions-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/exceptions-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8603480391b3656e7c9d83197dfaa9fb1a82681f GIT binary patch literal 275 zcmYk1F;BxV5QRG+w<48TDi$WfLKo`!x3GL%XcOc^ZOxljwo7i>q+e~+s$Fx}nL zz5Cu>EZ$*tcqRkz=ubOLM{1juo!8|R{umsRB_A2E7g3j7sGwSP0yyB;h%ud;6!N^E z_U`^!woC{phEY3f2yQ0CPKD2L0LZ+tN1ql@RD%jBHZ!=aI_t15Z=KbfZX#{M1j;pY z9)f0D_6EG7-X?iO)mr}%Wf!QINoj|YI%&wKd^$>vj=nkP&8#lx_v^E@D)Jl4zqDBp Q=6VYDN}*To$*CCmFWCrMx&QzG literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/from-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/from-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c2d87fe148d031237e782e4992a77999d72b5b06 GIT binary patch literal 269 zcmXYry-&k15XCznQ%J{(g^5fcq}KCw2?8QzD3z)(Ww6ePLoFO%@CT^>Jq}^IyQg>W z_b!(2us*&}3-DymdlgR9HEVrYqh>eqM z$7LmQPO+wk; P%a&QZN0YhDqmU8CVZn4Af9EFZzKk6@dR)%U!#e9ZaAd*bznr9p3IIFka#My=klWL-D zf)+dR21QA|Wpy;zTK^GM7pPZ^+8ITiYA88-j!GLxKSfd0vnrq8-JhdnmY!Jtxu%6| Pt|qY;3O%|tw@%F#$h6w@1Fe++A%8*9|M zpOEV?5%bKzRZwih-ho%-Op*tUo$()0_JN#CsH~RM%a(EzpQ2RS(hujnnbqa|?*0_5 YirnYoPdh(EdpU`{QgCRWEXK%x0oO}nL;wH) literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/max-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/Options/max-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..14a3571019eec12d70551da5dba3c104d9839dd8 GIT binary patch literal 261 zcmXYrF;BxV5Jo$oG$M=@3lm|X3-x>~K|rJo1*w85gLO_EYGM0=eG&BE<0zf(PWtY9 z?;`(%&EbVQfG2<2Yd%unZp^wVbBBK!WUqBoZfgwK;|buPe%WKq5>|d(NS#MhqO=6vAQX5tx>ySLF~dpNHYN*f=aa? zAS!Z()shC;k>^w$rP7vug%ItkDcASg`L!yN|J7M@R_v}9u{R11 J?X$%g#XsJqRI~s9 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/build_exception_matcher-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/build_exception_matcher-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..02476dd47b3f63d8d763dcbc2a4a2f9d715a79ec GIT binary patch literal 575 zcmZ`$O>fjN5bXhlWqU$YTj_> zZdC~Zr?I6s@4b2N-t3z=*}iv5h;ut`h&$KpPW1gMKb29Nrlwzt2G-8jJ+kV^XCnJh zR{84^JvKNBv89_xfu{%i@!9{@mRVVf;~`3;l@m`6nj7@jaS$RIh&@@JiR1Nvp2KeD z#Oa@yizImEapKpBi7jieYuL}Nyfl=R12xr9ZANwdm7rk%mrCICCQ zT&-4@FF{6ziEM@&5M&R__T02|jtLwomPzHYUlDt~IUJZldHocTlk zX{PuWUQU{#Si4?x-4Qn0UWK~#uCE!Tq1v@|3XD_Qp_XLa&!Q-HM^*mt`CWA3#YD1x XlzN`;TTS0mJwEjD+4&yL-e2(>EgQf( literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b7be1a2bc83187097b0a2d04b050fe3d404d64a4 GIT binary patch literal 255 zcmXBOF;BxV5Cz~4$dqKQSeOV4EY$OL2?8u-C_`1I4A$9ksDJ}fO4Fa zvzp*;(e@a=rx762(_nmBLs^d)QfyaH)V*~kv(Bn*ztG#T$a!Y?IViScN8mLLHp!F0 z&ibz?`#^(CsGO11OHDpyI!a|6{c+CQRZ|s@#{WK@zw0trFD^y%DfI2q?1RF9?$u$8 F{2!uxQf&YL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/cdesc-Retry.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/cdesc-Retry.ri new file mode 100644 index 0000000000000000000000000000000000000000..723ecdfad0497140a3888cb71d62d913d8cf96c8 GIT binary patch literal 1465 zcmah}-*3|}5Z(hyyI;VB1W4?`R7iWNLI+Gp&P&DELU6RXc&9Q^+&{f(W z&pCBR`61Ch#P<2VyZi3*-5Gx256|D~lJk$+G$4;9Serc%!*sNDj?OG19-W+~qy1Ab zP{D%pbNt?+b$;Q^NkrDix7IUJRTAf5&|5TrvIIW^bJew+Q>3mz<%WEF+JbR5i*zy= zCc|u3^ZnoNexit%2HIIf<|rM#KL%IM&@#L(v2{W#%Rp7kP#(e`Lph^OpB)1xMI#(m zOm$6xhUuC)(V&efuZzE8y^)}h*7A#4>R1Vi`JjYYAS<=1#bswGv$=3HLSbME;S89?TCSm}abJjaKK-?_ zoeqc}mkIc5-ebXpa%g^l^d~KvlDLLT^zMdI)r~@H8M#AM`H!1na9n2iY|Wpj1y(?L zrR$p2P&#dT@}_%%BkIZS$u%@BG2q?F@MpijqA7rQ9}uP6>F7z&Nvv?rD$Q<)4Ry1% zjQxsva#Xx(A@3_1vj(m?dqFJ-rExZiCr9Jp^^X1fx4NDGs@pprjaMb*%aRB>Abt2Z z&>HWYWyhU$x;a@XaLf)aNLAEz&QFZd=HOdEdmO5vN7GVESRBW}vWcqdmwabh`$y*{ zfzUxZ!i$;k3h!AZg-A*Lu_Qq%pW0CiLt5(wwxM7W5>|F z)9FipW3vP)e{J`yL~L_tbf?_vIJxh`Bzt{b(U;Y`IQG?FlUP1eUNph7q1d4A_Y-g< Ya1l)p($P+MDITwUv_7HFbk#}x3ChLAApigX literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/matcher;/cdesc-matcher;.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/matcher;/cdesc-matcher;.ri new file mode 100644 index 0000000000000000000000000000000000000000..9e847b0bb570aa70132bb7677c719a6586f169de GIT binary patch literal 424 zcmZ{hJx{|h5QZ}#$D}O_5)81AfstlDFOdqBGPFZ!Cl8V1T&RT;2ixJ}-{Z6tu^>xl zzdHN5yVqxQ2iKcNBLUXNwnDE=J!s^YiWcdt6<+SqG6LjjTcr0(VMQ&z05 l<1-lZ9C*rfoT?~04g1p+$!A4+`;V8Q%2Hna{gK7k_cs<8fJ6WQ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/Retry/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..85c0e02d9234a1ef13313dca84dcfb16c1bed846 GIT binary patch literal 1122 zcmZvc%Wu;_5XO5zY5L-TDkPwX!52~~ZC%7^BcxE8B1@#LO3Ecd*4iF7tM0?>uA79v zp7A3z6mm&6JO1XI-^}<~_m=J7oST%fPkK2=*qGb?hpaqkIrP>5K=w+DmQhEmO4_l2$Xpi=R%XOV2xaOrp z5E>k&MrRHZ^m9c0AE|I9^<^a$Tdp&sG&%=IFqu)Yt)=FIblaRJ_OK);x#|q0QVHfAQG5)5h*#Z_Vc=E>diUpWiEkaY8sM*D;+op~L&-!)R-_d#3V}PO@CKNXmWqG%%C|0YR}!xGFbk%(T?1gq zy2{x55X22rx}~lpo=<%0z#uNUz$A+l0VQJFP?D3%r1=>}QB z>(@3dm8??DGJ&Zq(_GftylK-6h1^BtG$MnDI{opemxP1d&d4fJpL!59T_$)=`&?i} zQJJLa{J&sU+^=zGrQ<6jJ#LiLm}@MIy9dKY@pq=tUXpOc>sGTm$0G>|Y=R8?I5N?p s?)o^;neFPs?CHhmnMG2cJJE5JhaTN{oP@)}YHbVo#qY1NkVPl(8{6)%x&QzG literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/header-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/header-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..9829d3c8525bd7e09806e96416e68cc10ad06c43 GIT binary patch literal 320 zcmZwCu}j1-6bA4cBp!A>M7X77QV<&)-y!r+3mwkks8fgV+NL&Knpcw)x&PkQx(LpX z@B6*)V*L)A;|tXQdwV{p&{0!v^kvSYPGO@Q1NNHb{4qm^4W0px>T^^+02Fjmc0Yzr z*`R9-nk>L?XveYwqG7Czt_ijaa6oq&2Y^W%`zf@BC>_uRU#{RPZM9K37e-e}yI6@^ zs3gpi#6Q%7tJsbeAX4gekh81phnKCRUIwg;lGMtYY?vf3D`n_Q2vM$bzP(Z#m`OQDerejuLFFW4I^=O_AdM~~K>{x6i literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/TokenAuthentication/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..dde0a5c331c5e9313ef0d24d9eaf88a21e4cc8fb GIT binary patch literal 319 zcmZwCPfNo<5QpI&Bn{?Tir^*Wq)^PBM}!o$kV8F`c*18 iW`5hHFR7O5ao#MFsrK%lwmGZaE-@cuM^vv0ont>zT5Ev- literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..01e16dadd9fb26daaa968e453253a265218d939c GIT binary patch literal 271 zcmYMvJx{|h5C-55$dqPasaV*8#K%HBUzZ?gqzq-K=#;_o$Awy4>|i^f{(Ax*SWkD) z``+2|0PFpW*8orMw8M1trd!+dw!F}ihymL+ZF$?sAdNf$?D2ELm;erewoZG4=H_p4 z!cb%EnPiOo2TrJ1X#fBK literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/cdesc-UrlEncoded.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/cdesc-UrlEncoded.ri new file mode 100644 index 0000000000000000000000000000000000000000..5024e95e9f709535ca9a8abf2231c9e5a63cb0cd GIT binary patch literal 731 zcma))J#X7E5Qa4rl58gm0;5fVPUVuV)=Ul+;5q;YyM-$w2sjWFMK?q#Q6;IQ`S&F) zIdwmVECh~s$M@xP_bT1NH``B|L%7kVVQQ(EwPY?+3@&y?ty->YQO7V|-C*$kh8b3~ zCkVIVM=z{{@T3OCzU1w5$y(O65|7M?*k?3+H^{7+`QCRBddK_CAq(Op#>7};C%StQn%Kz z){zStVQ{(pyeU_kl9qR0RsjSCi)Tdtp$OsM4S9a#f+j`gtruC5@PCJvlZYfF!C=b6 z48uQ2N)j{+_b}^>c7i)mAHuWF$Oq;`2rxL82h03GVQiX&#Dp`Yg6m=)!mEZket!gd zdj&46rQ@JJ{_eXRum0#j=Rq80{)_^?aX&mhCw}_P`s&?E-I7#BCj^Gs6&VI+ QBgP=ZuTFP(t?OQiU%f)w=l}o! literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/match_content_type-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/match_content_type-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..564ab84d25979879956e6cb397917e1aca2a8deb GIT binary patch literal 309 zcmZwCy-&k15C!lK$dqPasbF9W1F(<`OxGm{8Yx3NRCLN<`Qt(?9AB^Z9nnCzjOge4?JFMJI30#-$1ELQ2AH8N{v zE%P&$4c>B`u}3f2hP^>vP-h}c1z#16%jg zeRt=@99_WSk<$l7!GG}S&zn|;1Aa5a?Dyu87mW6 zi5c6F{_C!4?@W}Rs0K5A1UZs-GAeCR`cd|NiVF~=M(cm7uD%ld{?v!1v*~a1%r{R? K*=MUlsD1%42w&^~ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/process_request%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/UrlEncoded/process_request%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..17b028bb84ab2666da65728c61c785fb077c9b22 GIT binary patch literal 295 zcmZXPF;BxV5QRISP&GrB!on5?U}-GI>p&1RQid{Abjn~k&V^byzHqid{r3a~iGlS! zJ$>Ihn;&4ce+p@~;OU0^HCxHD_036tE zou(Gs>wlw7QkIYov9U%ITurE*;`cZJjNI6x3v)<|L2>Z)3>HOaELPc#HBH`4to+v@ zk8CAQs5LjqCV2%>P;Y`fqH2wM^Ri>=Wl)VpNuAW>!U*uPK}%mkheMC-pPrR}0AR}bjE9)HtyF@1A& U?mo?!x|vJ9`p^seY(h($ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/cdesc-Request.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/cdesc-Request.ri new file mode 100644 index 0000000000000000000000000000000000000000..02bb8d6cfd80e180c2c60e27b5c3bb4bbda68086 GIT binary patch literal 1536 zcmaJ>?@!Y}7~Tid6*fRa6cY%ZHKu}O8~W{v8k9ZvE*TxNFQw2$cTg67)7*6v>5Jl`XV zB;*?7@xEul_Rg_ZMXWo5UcJL9)gzf~A)FCCDqo7EIed&LNvJYkkxZ`PB{R*W$Tuv{ zI+1v_l5jxOMUi0)dWw_^ZR3`o5vB96DZQrc*YxY-Jv z!_%B5NK2GcU1X?G92^3DrHi*75&@VIMXHJ(G7cjq5J5Q+6s1H6sydb5_b&X(iMaT| z1Z_MB$uFuRqFLGmDeb^{<%1J~#wLiJOy(LT65YU+H}i%$aQ2ZA&;gCe9ci86ZkNlL z@DX6$E#wjx^*Ld4qG5lU;wFYihz$zZ08w1V& zKN{fv?g=u{Ol#~`iLJ;`{Tq`Kp37NM1q;mrf02hXrk{+nSlaOPuE^oA$2!zONJMZ{SgTIQ@3D@rtlL#Xvfh{0|#Q&K}p zXadwt+|Crc1XHsJoCPLwO+;*%%4@u(uw@RK;h7=#H_gHh&-!<(g*xaHTkR^m6FV&} z2UJ|%S=o^D@ydH@Zug#DsbTRW{>^sS25 vvtWus)NUa&g=%?0#s7r5vq&NDPzkY2=y(po46lc_DTsJwa?l^hq~P=)3^CIR literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/create-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/create-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..3e98419a9672ec27aff9552aa765389f3bdee8ef GIT binary patch literal 273 zcmXYsF>k^!6oeTngBnKYg1UHWmy-Fhq-q<<104`d8LVgL1uX11wH;Ob`-Ud#eY#I~ z4~rA54xe5FytlVKrHiktm6;2k=|Gr>0sATie=ad#jW>V;{qz(Qz{Gc~JVMs>${Ouq zGrIN|u6+kEhi%c*}aS2MxaFH<1h|E1SED6-+ma@s!xrG6UMe*56i Jeprk#{{!qTSnvP< literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/headers%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/headers%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b043483e9abcd7126b18dd66bb5931cbd9f038f0 GIT binary patch literal 357 zcmY+AK}*Ci5QRNRT&;RqysSv57X@*9o+4D#N)9VaSx-Hbw4H8)X%mxF?Z3C(E`rAy z-hA)9Ih?)2Jb6|Hz+>C5(ABC;=i-R@XEpK?jeQ_MUSj57#oX|c_W%igc4*!8pCBZ0 z44&?CDGCLP3Af_rqtgHbyKAs@Gw>qKjk76HaQR=e9?)CEbxp$KlraBwy<-7QP)lAQ zHIpUXTi#J^(4zSg?UuS4DgFrS#-Zl6rmojWLb8FAs1g#HzmOtdR#X1vo^@~XohFD> zBV0C;2Y}5gqnga|TwmB21_s7= zAHVnR4rgyL&z@BU@YoG&bX?W>TpXq0sb+??_MQNFNz(8#@v>$EK!zVZT6gu=Uy&q% zK=-8-m4d|tTQl?CYXDE~TkPBng4i!On-c{W|7SLyyfaL5vO3O58a{0HET9=`$tt9i z(=F8oEt*f!?Wp5O@mp9o3eGI2ZqP_pWD6&8BP6EbLW*+POsSV<3VmnF{Y(_AR=9#A zt3ALLjZtmkSShhkO;M@N`OLN`QL3*fit>Xr46a9;n{hop+xq|f{=pZL>U_HBRhgE_ JC&{dhegM3ZaZdmM literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Request/to_env-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Request/to_env-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ead007c89755128d3c7fd0169bcffbcd6f6f1073 GIT binary patch literal 1216 zcma)6%TL=d7~f$kk0PW=XcstmnKXe|pwh%)?lg58bVM5rmB*!r$Vt95)*L&t9a#6* z?{n+`6Bl}l?BC;i{OXsh*K})kta3`f$mJQ>N)_`hzLG>kt5T4+13EaFCehB6X;!c$ zr8D^5g0XMI^>{Fy(qYqPg6E2Ed#N*~f3*#zsN2>c?J6Bk8m6t8uPVCpKjs337n(KI zV7xZpOrp(`^BeLVmWB+*gR3O^Nb9aD5)($uvd)y?f1x1S*FnPVE?t0qPiUiz-3!#8 zG*iWr5Tx1)?it;ot(YZuTnGZUSYgYASdt7#uH-Ffiw0IXL#w%590b85+G>G%D0n?f z2$#k(nFA@6?i}(~YZU99dfEqyINKV>48NG1UR_-v&@@UKK%Wkfs{(@8HyS!jD_{j^ zWXGgprXs5JAx!Hz>8LpYo3>t`5foBCVNZ z3lxsM8!vs=N=nErSCVjpLm@q$)DP`^>f1qbZ>}0gGTr!a?j>KeZrYt_X#T*3;7P7- zKxfSIdIcjhOd?A08&qrkaATqxkcS$_L;8zET5y$Pbq3I@FzY^EN7RAS9v99>SQ3b=iT!`7%q!#OV2y#oQi-LHWUlA&5p~E>GI&}zd+SCSGY_F&b$@4n;kq3%=XHMLjAl+iItk*pDl@cdPi|L;^p6)nruQlf*&UFV9Cu zh6fZ{avFJ0HYC(@AvOIn#=1?ayPYvi_hq_4YN^k8o>pH^2_$bN&)21NvXKM84u2y0@X-fN*56FYV^Wro z^-&pJ6Rc)yE8Q{n03#ebv>}D8=%ow3TEIooYJ)sq8Lc+$EN^HQADkM&J+Oj09mD}; zqwTjBt)or^sSFBgMNKx0s22(i{V~R>1dXlY;1;CkO>UU=J!(dkV5-cc(VEn^}{rZU4PVKTtfF zK*G$M%)EJ%y?6>olRGK_p2#$^zOALTVx;0M8BOrBL+hSfr$}1{?EWE3P9LO^m0SV* zfjRSNwGF<~xHyN_hc-4xT~dYS@(fx-%ay+irK`)cu)wJXsdL^*E$aNoEU43!G(LPC zN3wJC3&z_t)X30sditE{i`ZaAj zx-vz`2kDp^mZ@29+oPo4ug>;2TEHfb&0#Dd>~i=V)1t4eO}IgSc`}c yLmqzM&z@k@ohrA1@6rLh_`-g0B38Y0r^l8(8y{xLa68FRsyzPv2_C8HYWxNi?4;!Y literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/ResourceNotFound/cdesc-ResourceNotFound.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/ResourceNotFound/cdesc-ResourceNotFound.ri new file mode 100644 index 0000000000000000000000000000000000000000..c41fe56694909980052b45a675f140f1a76cda27 GIT binary patch literal 426 zcmZXROH0Hs5XXCvw00jCQ4zsIKY-iwYj2aX_{&<&6Fhd@$F6bA%X-3 zhX3UEpT|YAhnw9K3VCKU!_LeII&&;5&4oB7sTKbL$-=NaKViEP}LXm6m~~RlR7B zjte=W9&H_HFOV15DPO%w-YE0xs@7sxd0uN-VOt3_KA>GyOO2m7z07Hvv*_?*7MEEn z#!*KSOIQq(eyFt)L62eHTl7+R*&NboZ`B9)a!kr>ri}C42zmZWC!;{8hd2u{Vq||F obvd^200TFSF@sYvZEC?cbAZuo<-c0orhYF8}}l literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..60f8701260f7f387bd1a80637a51dca61c7fd884 GIT binary patch literal 260 zcmXZWF;BxV6a?T7$dqQSy0E1SEX4Ec5(HR^L>a1f%3#^fOKR2ei);tfe@|!_PrCbb zcgqv35AS3EUj22C=}b+%w)a*3V3czV*oUa{tx!QV>I!hcIFOGB@JU^VVS8)sm=KT+ zqjuI1JkH);h08bqO!(NNPfN(kL4_3S1+2=}I-Fo{#X5{B_F0Z02)c6nf>} IoQjeE0#TJzDgXcg literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/cdesc-Logger.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/cdesc-Logger.ri new file mode 100644 index 0000000000000000000000000000000000000000..facfc368100c732e8713cc2b77093b709dd6009a GIT binary patch literal 581 zcma)4J5R$f5bl7Iv}vm%B#=O22s_PuULqADMWPIaP97pBxfBb>jvR-=zsF8n!N7n# z*?0H7&S$|EE;kRV1b9}uVPYj%*U<|eWKsB}c01G_c#mlo-KI>lihTiWuxpj<5a8HA zJX??csIPfd3EVS{p6yX^b6{FC{oc0#mbPzDngGJ2W!iMqQ^XHQKu0i1YA!H~?gTHE z^?`b+kIYLkD7)8%#eIc1Q4Kfw8?uVaU6Y>_H$ z^RAqE$8yS(jFY*w?b^1dHLP4Pp9bK?3g$}EfREyzfgvU@nP<`TxLQY4Uj6OOst!YBz+Od_KL{06rw#x+jGkOXfHxWj z4C{aG4HE(`ebC=3A;Iko*sAa~dVq;GT6Ad%S?N_sv0lJM*=vJUzBalk`k7LM6QnRl z#$#yMhJ64p$?9}e({6~e4`gLhjX_DhY{{i*Jjwk REZUn{@STEH=Gmwi`7i#8T7%q!zm#BDj>gD2UDcicnDx3ZBDJrw-vwoA!cf-jJjm_w8+s`@@g_ zbCG_-_V7*}z^gg$WjIpbZq;R7q(+_+NIsgnxZ9z_9?t*==`9&A0X}IQr2|-3&&jTV z%+5lqj^H+Odvrgu1z7BPk|v~(RTf?F?FO!@L20?bT8VOqc3f60x~535yW%b6^euhHFg OO#LD^p?=foJ^Kaa8CZk> literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/on_complete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Logger/on_complete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e888d03b04af30cab4f7a5a9609ab6032310f96e GIT binary patch literal 274 zcmYk1F;BxV5QRISv}%?P6$@Ls00Z%SU4j5hktjn2QwGaPE~$m>vup>{e~%#y9Z!1i zecxTJK45!%rVilIo(~vL)HhqTtcwj<(UEZ)BW94j@VdC?(#u|+0gf0P*?<7AG>+(Z zm*IWJIpl6?wdx3N=JkX0pOXVfsL7y>E66J+eGJV4*43ai*2PY%wj5?g>HiU>{v$m2 zHrr?Kz$!8-iWACS*)fR0lMzw28U+nW*v2#-M2nif8Dq_&F4nhbzwUn9Ri3`cXXSMB Q?s}GcBX6XB(lP}013(;F8~^|S literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b07614c7b3ff225039a78c02009a2d2d198d5807 GIT binary patch literal 261 zcmYL@F;BxV6ofk$OfxC9BlXOt4gzX)bGHb?P)@Lhd5miEuX}Ub}qaCt)Xdra2}O5FfhDHWNIzc^?Li zl7{7m6>ZpS6#t}#xgZJqyw--+IXgbZJ<<|h=2QrKY3=+^x8t~$wH4?*Fpg#(KM)`H v9X}q}-6LpqG=Ap#_%Z-*RuGpp3Ah&>EcXswq4*{Vho=!9$LyH%zyIV1;!v+f literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/on_complete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/Middleware/on_complete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..402522ec8cbd784d3eec920097b84dc5ef02c7e4 GIT binary patch literal 428 zcmY+AJx{|h5QZ60DD6;&iiHkVSjy67zAiz9NEuoXf+<7l#OKDs@kO@Vs{bCh1p%W^ z@5kf!viAX_w?e9^tCJ{6sa3vgkPBrtu9TMA z((_7VNixi6d_Z$$g_`zBk`xzt+@A#Mhod_khHZzxLxx*c-=61Kk!`tNXzpC{1%hRc A_5c6? literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/cdesc-RaiseError.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/cdesc-RaiseError.ri new file mode 100644 index 0000000000000000000000000000000000000000..0e594716ca13fcea625e5aa6372d00c834917cef GIT binary patch literal 681 zcma))Jx{|h5QaOTB$N`6iU5ht6Jns*kj_h_0#b%Dv@m&yoa71?P8`_|AO9XZDWVc8 zVzGSk-M#ld=e_6&PM5c;1b9%o=5j8%F>ETLj2tbwFnFi6(g6f__ZcDgT=R;50xZ$A zsxjzpKS?y$k+Tq0CGnkW3|x+ai$QV0^=sDxIQg!|#zt_Ewp?4o0!71!Mr;J*bS)%i z2?CNEH` z_k`{zbeyme3!Y#)3^jMQEN?735~GZq&!uqrJ%p9zwliqFhm73($pT z#M3wp%ik;TLxn8N$hhqqx8u8 zQaTwL9;?P-s9TA)U&sI1`nD(E?DID+y8%Xe#X@@MWohirp5|u7j;6&A3$Su?3e~Vk ajJ62$^n*0c$Yg`l!!6IYf8;_{oy0H0&C{F! literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/on_complete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/RaiseError/on_complete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d0a7839a62cac9b2700bf69723bac1e8a076cec1 GIT binary patch literal 287 zcmYk%F;BxV5Cz~4C{)b=L&d@tma;USuS*a#Qid{AFlDfuI!f~KalenFQq;1 znTenN7j{WmLOP6%(JjH_EF2VH#sMI5qeT~%kQRgD;Ohmfie4M6vW?MA-p@|Xzf8`P zB5`82+$6i?14Kbq2YE)-X?OCnXR(eb4sTooyx8lW{F$3F(#s-_gj~ABWzS zZ@>9om#w+%%sy!;<$JZ8pera_bkx;2ya!|SE@Awu(Yineqj(%X$H0)mPRbctLzTs+ zbJ`$?W7#%!s@0O@<3V`>{979-y-i(WERlrmB^|t+K9pP=&T9fz4ySXAd96iG zEcU@0!m*<8k)X5!a)<0e>xi3g5GAlJKx@pzsdlf?lQ+X$X&i@LttGCjs5|%)SbHk literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/body-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/body-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..99ad14dd2ba8ea6d01fc1ffc50e0a515017e8651 GIT binary patch literal 244 zcmXxeF>k^!5Qbrf%At+eP!~F-OS^#QV@Xx8lmQ0RP8qCo;uNcnFR~q>{Cm;{*86mi z-iP@&EKfVC06yGs(D6)lxim?UJu0dP25c{iY$ecRjRU|*hmKs(um9_o2?1%>D{Cr( z)#Mz||Mnfgi1w{^aSmzTp^u@Q!BgHCtBdT#8ntOAbmMR4+AFqYU%+!}O_XPiwQ)Z| zHlA7;QCTgikrlZ(szEAk>B2cLXGNC0z5l)D=@`4XH;xxkJx@_b@-5m=iy`nU@MKO? literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/cdesc-Response.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/cdesc-Response.ri new file mode 100644 index 0000000000000000000000000000000000000000..327b53b1c7c1ea00869579dafdd98c5d2935ec94 GIT binary patch literal 937 zcmZvb!Ef3y6vjDBNg%+=D$&Ds$}T$%&dy<(x}oMkC$aYAL*&E{@aEW_?UeD~&n}_K zP!-9NpPzs4`Fmg9M2~2``6erb?xn5?zvaXje9fXfnQXu)DGUTC_`b@M`HE;l$q}KK zgEVmQ_(%B*DjTH1gGBF7ur<-Y8-f0UBjn#vxBWa8@q1 zC-#CgR&q(`XI*+AT4u6lw%7xqOzcdt)v_)uDLE8!TU1h5M>jh>iq zH61O};nJ-*z@t2gKs@#!9m%V!>~m(o7gjLTYvD5D8-M3hCdA$ukgyl@?=;_ zdhE9GmI-F|U0`|&0R7U%#$H3vzRi|0tBE#y!VB8e>XopcLl?f1!s%Tr4%YYCGGf=b zZFKf@uRTO_S=ir pQ6~aQqXf00CL2c83#klUvm#$`mONEH3hQJFI+E+q>P1FDY literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/finish-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/finish-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c722c4f80c759231d003454d9eaceee02762c398 GIT binary patch literal 251 zcmXxeF;BxV5QgCnm8lwat5^z4SYT;AUzbz`OBu>g!IZ(WlQXe!e39*d`tJ!!yWXdJ z^v)Nbus*+14RG+66Q-7$YHjbzJTunY*fL;mqRbzK3aU{TfHTIPe8i{gzGp%})(_g* znqV_oCl$Vj9$QSj}Kr80)aiADq=YGqJmHRkuO2J^KJ&P-l~DQ8m_o zMQH+cGAZp)l94s}G^$Z*bo9$PuV!Vwd`AEC^8a0AWAW-1I$lJ5KXtuR=#)D;6(j!x Ddbv?a literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/finished%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/finished%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6e5c684a771a0237c7998213ea42115b34aab58c GIT binary patch literal 254 zcmYMuF;BxV5QgCnm0J0mWr+r#NR`eKBtY&ak80&PI-#e?eW|Ftz7k&zg?bs1`L7h#q z)!1178Knu-$%M*jNk-P>)2K$Nw4*Q1c{MBZ#pCAZwaCWe>%Y+PBI?^I>Vrau?$u$8 F{2O>DQWF3G literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/headers-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5e081a931b081a32cecbadd9580c47d58b506ad7 GIT binary patch literal 250 zcmXxeu};G<5P;zhm0Jf4hlbUodD z_s^F{SnWT!2H5)Zj?#&nYGoH?etRNpC`19`QbXaEV#2tU!GY1 z9d#SH(+Q0u&8@E4r%{dCkmFw|Wi>1F#mnpEw8+NZyKCk+QT6>4^~Iq>_wF!8`3EEA BP_+O6 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/marshal_dump-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/marshal_dump-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2a4e89bd98a7b4687a100b3ff02941e89b3fe8ca GIT binary patch literal 349 zcmY+AF;BxV5QQ0#Tc|)ns#xd{r3)-HBXXA@AX0`RRKb+NIy;vps_nCEN2vdvK+4ed z^zOayz4Pf8pKo7DasF%%8;mX0)x4XO>5Ty&TF|2Ijbog>6=k|Cz(WlO&bJsG*?`Lv z)tVIrpSfP@P7%KweK+9uz2kfc=?&UA<+I#@kD+437pIz!!GGt$wQPM+u`+#_90PVEyYA)a^%ohvo-tVmwD4^EYpSVmKvwh^QmkgMELvlAnLk*g_U#1UhhO$CD0X0PzzcFF z$xdTq{CkvbASV+lt0lFvCZ9%XluBFr;+$8rGGA`B|9t#e7uo22`=>i5qQ0BFUMV=V IPZne3-y_aeApigX literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..03335a36e5cf335eb7c4462dedc63d370b411662 GIT binary patch literal 252 zcmXxeu}i~16oBy#B?g1wP`cEi+@y=W`H7HH4ct(N5~mEuUGicNFZaUT#nS)Ygy{Ui zk8hcN!s_%!HNf6oj~LI?R4a2MSnBYSK=NJ+wkecXjk*GyF!baC0!;NKDN4xtL0eN3 zY-Z-D{P)lUjONgxiz#GzuY3&E0&erxSQPBR8og_0bm#xfXRk-G1fEl8qCBH&jQa|* z_0-9zv_(m+tjWbu4N{|}3+KFA2zLL7?q~bDb;dqTMxGUd-Tlu_pY?ja`yk&bd$1}5 F{tJ6oQ3(J5 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/on_complete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/on_complete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7dcbe62bd585306e0dcf74a96dce16256e015f77 GIT binary patch literal 267 zcmYk0F;BxV5QRISG$KOkP_e*d7FgQM*ChzB}|Oc^XYxljwoXW0&@{~lKXiS6`s z?|a`x`3~#DGj#xu?zG2rq`qC7rC=*^vZK*kOjtni!Ubbo1=Xt)zyYHt7xC`@)2`qg zDnDs!I)a;-x>wZ93V!MFLW-t~7yR}Adhnc+%zvxZS#jbdRx}nh| zc|_G4_Yvg~Xp~85i;{+H=u)OesnODRT?f6Ng%Le38!)>c1x_WxY@L z=$$XWV10U{8sHGFN1M*nRBN{=^NbUwfdzNXm&7oQ*t>Ri%ii;WB4 ztlLPPPH4Q<)asf-8dcWDdis%4Rs=lA1J}7qRUp+F*U#)Ub ALjV8( literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Response/success%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Response/success%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..839311f70b126e422577e88e1822680dc93e60c3 GIT binary patch literal 252 zcmX}mF;BxV5QgCn$gPOFRV*MOg#{Ms`8p5;Sjtd_3Z@K}?OdpZ4t249#IUUYqtZ=oq`@2dp{Emq6A+VBMizPd)_4aW*q23XZdne?O;b%PYFiUG~lxH)#T-TG*T8;8gwj_+a zL6TylUGbqrrQ7$us4X^y6QxlF)`i5@dFs9>mBH_X-6m|7@Zj`99_H~(j@CvdPI(CP zZYYhG9uHyJS#(M|Rh`nPv-(RoH70%yy6v54rMk4T`3SJ+6c;`QoE$G!vvG_c=Xd1! fG`5`TAi0=44@J^t9!KY`dDgAG|9^rVR)bN0$%J_= literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/SSLOptions/cdesc-SSLOptions.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/SSLOptions/cdesc-SSLOptions.ri new file mode 100644 index 0000000000000000000000000000000000000000..b1a334fb2be46032c471cbdea074055bb280e937 GIT binary patch literal 612 zcmaJ<%Sy#C5WRx5^*(eVsNhEGMnSae$-=@_q2L32tg;Acnrbj@N|Nj2OZ;6YZ7;a8 zfijabIWy-Zo5>68Jzg0BaBpnG^-^=^=&nkNbm!^m_M!92v@U|^`ld(^Zn)(Y{|5L2 zkqD8EpRw}1m7gc@A+4&v&yGNFRx2%ssN?<(qXA@%sc=7hAf)xod1L!Rtz_$2*bB#o z>|OS3xTk6*xDSP$RUa6!0UKE>*{z#6ocuH*(X)ZWLE;^^@2d^~^{yIhlE5tQxb==k zhQtX;=me&D7`R9ewJI;_LGOhbY&f@N;DanTjq>bG@=CR@j@8yQ%=1!9W@;u(>yg~C zQfl*=k*$nOGdk&4OyeS*iePeJq6v**)~!md1mZDlch-0*ysY|kK57g}kuFs0Ja2_u zA0;!|6D}&{LibAq@G|}xJ{Z`T6!eAj3fCy-<<`WT84+-J41I!|ZTs8v1CD;n4ruh^P>0ney0 zQJyqb#{C3Ydun97L`kY;NiOzikV;$n|>cw4L&Tj`RYM|g0oSu3JFKyz2XtM}r$ACSFGQScSu)zV~aCm<0k|iIn|0X*o z1Y}*WoUIAglefq4)pr0R-nZJP1!P5sA;oG2=Y_FOm-*URwKbExrAfUFitX4t@Pb;K z^i+Hq~I7DQW8Jzc<+r(TfBI z!jpO5cP1Bf2RF}8SOIL%wn8to=zD&xXr5ecRV#6DOKZ^*Aj?&r+^>WcwfF+~0~zt` z?uRY3lIGOs5yHdKVlC|Z&;fYAq4h5)jI&Ny*K>j_ri}6kMp>h@^lDm_^XBL_mm$KV zEeRuANHc7eE8e82m3i%p#$sDIQEFLWQ&ec2m+p&FYTT#nGG(KbM~4&hI8R1Z7%?bu z%3~OJL#b88Nnq5-eIWnX`<7W}(aFlm+N;Je>8$z?PKHaKOqJ=KFqJ$zuyFuva;Q^Z tBTjbbjVwaiPY3Yg^%NRTRg|80amr4zS)NQz%k`?O>h|}Kt+5`o{02)Ph?f8W literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/TimeoutError/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/TimeoutError/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..b94a1ee4bb5af83d0e326ee837f304cbd6face3f GIT binary patch literal 256 zcmYk$u}i~16oBy#5`!5;D1taxGTFu6{6vUo3mNJl>6GEPOJ3~Z-M#ScLhXNVLYD3y zKfbH<0L$-BY5?B-d5`f(ZM`(tWuAIGC6H{ZGJo1BR;@Y%RK_62>d?Hx#c6y)v&xiLk*$MV|OC0iwr!nf6T#a^Z H(R+RcXi!c; literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/%5b%5d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b2b45147a9fa500cf45b999de64565114bb480a5 GIT binary patch literal 243 zcmXZWF>Avx5QgCl#W8WmP$(S=%F-^4=Ii3p)%Oq{lorfMEvO}x8kV2OC=z=e2u*e%@wP4TIsC6^J>tS?1oQm85cuuVe@)So* z_wQxnsFeYg)sh-nQ5PcVrP7uzobz%fSo(H;AAj@gAlTzQZ)~fcrlK9W7VWo1@A(Y} CAx!`P literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/cdesc-Headers.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/cdesc-Headers.ri new file mode 100644 index 0000000000000000000000000000000000000000..f6a3e4227aa8b98ada2ea0433f1c82ea4f984281 GIT binary patch literal 926 zcmZ{j(Qnf*5XSp}(llu|Rh2-9J%nfyLI{>;M?lbET7-(wpikBmInK4U>cp1qF#6wP zrzvegdr5S;^Y{Jke0kz8(9^rmf+F-ysG9I=PPE1|=I8PF7Dxq3d&v88lgAe~M3IVY z5n33=HA4Gz>e=k*mgu#YdOrnvvD2FqwP__nR=lmDF+K`2NtDsp6Y0=Tefvfir?ua$ z#Yz!rm25hXUw^8IG*CrLCFOU5COpL14TEqA0>tpk0hO2>tgOw`O2 zYuglSR=RMKg&`$}LM#g^8e<`KQ34kaNg5<+nBW2S7HGC(ycUf%q%ruM4e~hr3fno6 zR@pXx`N(JxI#eae->%b9-`=I()}`Rl+Yga8%2Gu&krGt&CZdF{!EvWSHnk|(G#k?Y zZ^|JK@i31A>MqV5z&;+LP_`v!be9{sR(GV2j>l>E4Lmr7?3GnGlS&w%cKFT$jiqA0 zhyfSm@q~4=pdFzzOec8e5<`6NjGThi!}sqGQCI;7<4*MHU*@RvE@}LmdE!0N^V+E3vu9x0pY(!yUj@ZIh zR<`>+S$gK?ke=ITw<7(@+Z8eJ+aUDA4vvWi`)shk_Cdc=UN+6++3CVKHu~)NH=K*A Gk^!5CvccWTK`cs)V|krCo~WV@UVXawOc|_masdk`j%-I2|Gq(CeY*GE zn`b9j{_cGR@Y&rClrFw5mv*6eUX!Cl4A_@cd@V6xjW>W(vMvIA6V?>s`f;^oQbOJj z#@Wil>m(j9T!$WDV?7&8C^~&2YCrf?->B1X1|bCVd$n z+3p;56MU-^8b{hUy7FBb$*2uE|0jefXNqTU*Y|t3$d8IYKPHZWtX`%?KR&eRb`E0{ E|1)S%egFUf literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/fetch-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/fetch-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1e08fcabaede7f8cc077463cacdf2a6ed011a53a GIT binary patch literal 264 zcmXZW!Arw17zOYhB#zbNP{hlKAS%Q4{OwXv!*ZAh*-kx#Bu&=Pv|mY5WdFS#_4;`H z-n*I~Vfpik8sNP(}guj*96EHw>B$YP;t7>$$5be8@vG=gCP&_sj<;6g}>646$i+M zsL0e7o+jKL-6akHi5)xLhXrK$fG+rI2KRYuNSFMPjM}sldlN_Wt5a;t4j^*dnIO+; z$Mh#J#~m3^k(RcVwe3SfdZ{$oA0b3FEBWgAiWK$B_@8IVdi8Ia4n_SiS$$d8A?*mg F7r%LLQ3L=0 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/has_key%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/has_key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f51f57f70ddec7b89210652d5be641a6ed18bd61 GIT binary patch literal 255 zcmX|*F>Avx6ofMb)zs-00->8qp;;QuFGF0~ifTxQl1v`NlP%Z6vSlQh;(uQUm#)X% z_uVqN!20XW6#y^Yc+#F7pS>anat4;U z)=%|pQQ`mq literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/include%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/include%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..312512a9c0ef365600f4d8ae84e5f5588f03ddb6 GIT binary patch literal 346 zcmZ{gF;BxV5QRIS;5KEekPurC5-im7d1w$2k)aHTP8lpaxezOM9NCUg{ym9;*t*`k z``*2GK~Avye6=OOb2lC_G`1>s>M~ERR9EVu!b1enTb3vHnQ)>KBfu#r?E&6VROtNO z{~n974B~!}T9p=V7wS>CcIW{ni@{(Q2*hbGT=2yTHfgOi=E;p#a$hg_{V>y?oQzoX z1vIrr1>Q_ns{8i5cGmD9q(*LQUfM29NY5o|`$H)$NHKrj2+vy_4>Q6tLfE=ku}vDY sn9lmvppod#$?G$xc|soA$C;VNQy<&E{L>&Sua~eN))}E+wD6w(0wIZHwEzGB literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/key%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..55f42ae240de15240acc1988bf4580a0adae3240 GIT binary patch literal 247 zcmXZWF;BxV5Cz~4$OOVzAt5Hr0t@wg9S8y}Jd^>oQwHmtIMj-hi)=?I|DKevKHdB7 zon;4Df4xx!@X}8^n~qeMYj>{rMQf*L2JC&W_?^UnHBJDB{(D@7uBW^2 z?&jG67T@pG0Brm74&#y9dSPy=;?AMd=wBJIk9}1<3guO+&H#sKYykK~)uIm%SKEdO z0r@a$YZ`*p#M~)=8V7(>FgomG26;IsA45HZ+p;qjt72)5UUw6HJzn51Ub79`124&$ zD37Vh^gls%o}7$ITa?tvhWeP0L29)0%Q>%SRgpcNo-f%l7wN+P#w3X5ep>WJ-YNTL HRS5hK$=6W` literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/merge%21-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/merge%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3ee3befc6163f45e0004be5559043b160abbe934 GIT binary patch literal 285 zcmXZXJx{|h5C-55$b`CMg@l+$7g(t0^AZF^WM~IOrwo>pTp9}}7x_b||DHtYdUty6 zeQ%NzY`;IK26!7T2MirG<<{I5Deuvp@reQZ%!_oFYo{B10XPL?J-`?02A$tsuO!QJ z;A5<;sR7lx z-z`tDIet(B@HSizn0jjKjlHk<%40Yq1NJE^&ZQ2z)mMO1vMvIAp>8q6r+I15q=aIe zjI#~F~M~%3*=SO#-XB4H8iA5MrF{^uMnbMRDAtRsmJhgyDy7ez5cJv1KDins&5KjyLYE! F6o1liQDXoA literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/Headers/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..fb3f32d99c39eb82478881a472666cb1b694c6a1 GIT binary patch literal 255 zcmXZWF-yci5QgC^BnD$69D>-KskHI79uXqyVT!YmT$N&(O*Uq6vJ-YU9QW_tkn5%x zp6|U#53v6E;0EB$p7uKQ+}3MzS>~zL#{`nks>~mD=&;2Tz#$m&0ACtg?cy>2yd=8{ zvT;&m8ixA?+oSuNMt~?!gSH`stQgS+U$5Y*=nUyHzayiz-9m4tS$=jZautYz2NPr; zXN>*zvU5DhfQq!_PBv^qB)wFc_$Y*^S7m9ZfWucz0ODe!3LpxM-%3#^arL}N!k?jce-{UB(r+4pr z53390=MSm@4*mUz@kULR+hxhugZ2R#uuoZXF16Q<%+Q`m3E40j zXKRAz*>}|bXB+^MeC)7~E69q3$51U`U9{F=$v4iLT|2vXIGbvt#wr8x6bNaJJWa51-|uK?8PS(CHFR} zEk^!6oeTngBnJJRCP-kU;)pMB~@Fi8DKy#Ww4$Thgfy;BHK~Lzpqisdb<1W zdzxKfar&eZ;Jv#YbZDq57G|2K^FXpe-!NcbB2QNW9aeY)xCCQ8z_-RqJOB2m?U@je z^nysRvWAH^u-#rt4I27xWl(ju{}Ej&!{y) zHu1@HS1)TvtqiEFmQ>4G%W5Cw3C%0*2_gj974OIg74v7~}p%|HhPQwHmtIK--xi~OOA|Gq|HeY*R- z_cXu2;&h-I;B&Ygb?B(67UsFkvp6;wGz0c^F7uT@hYj8UF2Pt2@U5}Y&aWOB)vU~4KPYtCt?&OuCQ|U2nF3KSr&T}XdbE3s G-t&L9xl&mG literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/%5b%5d%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..12d5732eadf6440b4b8bdcf2104df24d513e8bc7 GIT binary patch literal 260 zcmYMu&r8EF7{>7(q!xP^!VtuZWETZ-Ilm%Q)M5^kA={})c+;jfENM!9DE;r((u2nb z9zJ}}(gUo%-fRW%(hXY~T3eSZbi zQWTK&QD{|JxS6>vx?}7CMmrkWg%q;9M;Cm#fQ!6QS~7C2mDn^hzKN6l=)}nFf#%kz zz*~v6>V7A8^F{!vQH1tXVtM>#y){-TcZenRqW&&cw>b?U6H O=DJVo4C+^n-qRC@Zc{1% literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/%5b%5d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..167a88bf6007c3f744dd23bc5af2f878335ccd92 GIT binary patch literal 251 zcmYMuu}j1-6vy!!q<35gmqQS@xai_#el8WYnBnA*yQxTcX;T|6=_^T!^uITygX4qW z`|!QmoMHF%Mm4}oKOJ=JsHt{lE!evH&LDd)1!E<8Y;XcNM`HuPG2JeFVCe4C=s7D( z$cIr`Qxn`R*a7`z8~~C$I^D+&VtNLAIWpjHs-Z)XJLrn8+ZNw)D$6uU3L>A1-=&oWG0wB-r(T;~ZGuELorA9okom GA@D!A%}_o7 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/cdesc-ParamsHash.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/cdesc-ParamsHash.ri new file mode 100644 index 0000000000000000000000000000000000000000..e170d4265de73993b6feb08084404d30e6fc1628 GIT binary patch literal 747 zcmZ`%!EV$r5ZwcE(#>uuR01K8SaRSWw%EL_u9Kfmgd((l@|LR~6hEkBoG7C-+XjA-pQVH-lp)pZuXzs5`@ zwv?`&RF={M1S1GI8NrPF*7WU;^+uSxp{Eo_3@vmnq*2-n<18nd1tAOZPv0G5J?qAZ zz9GJhV;hvPdXTPJS!ZOok+pYc=k!7Kb^iV=~dx|J?( zKvdXn^V;Y(ccM^`>pCxW=TMr>3sCwYVe^DV37?H$z=JHFm);f6#6up?s2>U?ORNX< zv^Uy8>7W|JMQ`N2aNvV1Udqlo(Uq`oWefh&7Xp5ZDKzZAl07Qqx1T*M{ph2p0tL=f zO^GGilA{S1IN*W>iRplIkTbYtJemfjb3%86g-41K=`s=_RsK3kf1$lncRZA{ cWV)Hz^hP9ok;Ui7SLvzB*M~QKqpLx|BUzf&`2YX_ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/convert_key-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/convert_key-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..149be3cf1d0a33c3c45f30a6630abd531a07db89 GIT binary patch literal 270 zcmYk0F;BxV5QRG+Q?*F#P$408y|UfN-&LPJ%)($`tCEU7&y7vxb54A{HKlC?mG6%GLVpp6IkirM-P z^v%Qn_Ld0&H=WZb42s}>+~1))_8mZk^;WfE3iGr>7koZ}Sz2qOvgFR_VpETlO@D?w zyMk@m5Ac+%4zf{L>Gt4d?a0c2g;A1f8R;QTdRZt#znt@Yk|ndpsQz^RPUq2naj}gz QQQnSPpX4l>SA*X3KgfGnp#T5? literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/delete-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/delete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..12ca1276b7f0910b82c62c5aafcbee23b7bad52e GIT binary patch literal 259 zcmYL@F>Avx6ofMrCB#FQP$=D0DD9GHepy`Fih4*XC7C>kC;Pb;kt`$06#x4=xX|&A zyYKF5b%M>;tFHi_yYWD&^>w*1%YtV$SxUr!y~%<&bonvhXxvi?U1Q7#I;emv9obZO_=vEbMLKPOLCH}kCz L9~{~ji!q8{0G?C4 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/has_key%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/has_key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ab836d9447ed4db10ae2d7b48b3af3cc310a7938 GIT binary patch literal 263 zcmYL@!Arw16vlUuI99~V5X4)&%!|wU?O;U><}eZ2PCbN|Hnm|%Q<40=(|>wnXHs0jJ0+j z=$iH4C=Id<;;!dPmIfYY@E+~C?*K-ZUW?X;5T_kl?}`OPX)Tq=lLsaFww@if{bcZL zc|e0Bkkn}DStGEL?YCpKHJW+kN-$Hi(zJd=I>v=EKZKAXET-@cI(8PrZbBFuhICmh xXq3h@CX;@nh33Lul9v}&^Ca4g($hpu<71xO{Xb#sW##>R@u#sG)vH41$S=k*XaN8K literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/key%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..24c19bb77e737080e67e84849dab9967eab16e41 GIT binary patch literal 255 zcmYMuu};G<5P;zh$dqPasgMwxVSt5tz77Nd79NTaYNrg=IdOftQPdz8ntO>eKVf$$DqiT?17cu znIt=njp@ImY=d_)p|V=~R@S~xnT%3t>wg$y)k4tKeU5oJeU}9n^zy$l?|6MRXMOnK K(7srVk^KTq*-_#E literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/member%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/member%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..679e8be0cbefff26717c6020c68e9c1aafa66ed0 GIT binary patch literal 261 zcmYL@!Arw17{zxOajb%uF%WO@pk7?g-wsyPU=ABYwo?z`OPkuTq$x>?^uM>Gh{yMM z@Auw(ae~#?yDtG=+hM0u<+`Z?*PV)-sv_iAj>-pDHbzW=C!d}&|7QNrk(~i{e}M=6xos^ zu-rS7WTUY%?RS)Q@J=RFR!d*Y(zj_uMya&*Ka8=&E{R7L;* literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/merge%21-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/merge%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4a689cde8bb0e9e5aea3bef906aa382d1302881f GIT binary patch literal 262 zcmYMuK}*9h6u|KvBo52)G6eBt1ksDj`R!6sgE>rOY^NT=OPj92q$x>??Ax1BVaNA) z{NDd!zK7-Z-PZuG{c)pH=bLJ2E(I-|4hMZtfPCx(edHLh!6U#v85;q<^X%d$#_r+& za7{ReVi=V*wTHV2-C+0`2Y~!xbh=M-D9Qmtiq#CR%GOvd=&dzs)lU9uJn=6Avx5QgClK?yOXO9+&1E`@e!G+!2%wxS+VN@*q!;$+LQh~zVpOv%5mf`^Rv zaXh^9_e3Kqd<=ho&gTg*Z}aIZWlf=bPvtBPy#UwX&u@CNfB+E&XxMt67=fJS9GbJzsz#OXauM(zJf{)NdCQBbI{`q z!+UQ|=6hJaKbr>NQIA{ny=m*EIIXgCh4z5-E1(?-ke9N`ZcAoa%SM2`7t#T|#aX#m z=K8Du*BernkPLxK(HK}w_${-aVE~A(piuicB*nn2cl8X;icUzZvP&uWx|<~HaCF>T zPB!EN^1>+LX^*TG`rv41jiR1$iPUtoG1^C@qa3CA&hxyURoUwLxBV_f-Ix|_`jBcN cZ;rSkiQg>#>f^3#E~d_%v5Ltj$(+l70Em5F1^@s6 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/replace-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/replace-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c8b4fe580b602b03e49e3710aba71500751ee128 GIT binary patch literal 263 zcmYL@F;BxV5QRG+Q;|w66%t|#1F%rf*ChzB$WVk(J7uuWjzcW$Tx2^!{r9+v5aT<& z``&l9Jiz+%g*3p^aNL>HQ`@ZVd0no8869fFfW3;kyb~C(#UsEWSr-95a`y2JV}JYC z+%h4c7$@bdCb*fgI}G2`2#_}>Z-%slq8c%z*eu|p>Z~($dF`y)bo0PwI`JQaVq3Nc zUXiy+_6A!!d_~y>@-m@vMp7p=4Jjj|RL0Q{=e${D@q0?W2@j|Ls>te>|El>W^wli( MPQjylb{Hf71%kCzT>t<8 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/to_query-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/ParamsHash/to_query-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7b45c21fb4dd2a3eab64bbfc1bcf00cba758bdcb GIT binary patch literal 273 zcmYL^O-sZu6h&ttb+8O>iXd)=x*0c4)^89hYO#wE8JtxYAxTpkO!8_zkp6o!6m)qX zk8|!lTOOe}Jfi@3w9{UO0lT(P=S{f^NWY_WQwG^f-ISY}Io7cW;24zl0PiUq|H}Mu z`}exb>KgJfa;*fy%?#c%_Z3HgWQj)Fu!OuCnG3#Mz(v(7Et~RME57Y#!#17-_l{?~ z>;p)JMg=-Z)+zhxY46a`z_^wadn(X|g!Gh4jX#8tcF~l@Mp}WLbnAz;Rr>D4sq(bp V^1pMs)#7R{_=e6f{iK=qzuu}%;-gCMS~Ai8m~zS&gNVizMK&Z>)W+oscC(v&=q`S+$&aCsk` z?|diO9yXsZwgq?^k2@I#+tnL&TIDoO9R^8&yp~mdSE9oXj{y6ivE)BenfujMb!`#f@|ac{2kn&oX{iulTy4oU$rE gzfa-G`(eHoG!?t}FOqg;d%1YOTW3%|YxJJ|0_<~J6#xJL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/URI-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/URI-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..aaa8a16ea24c986ea1de28af92b8f59fddba6720 GIT binary patch literal 422 zcmZXQO-sW-5QaTStSNY^6s?CPUfP3g@VLFCqJe-FiT0F3*iAOg(#=lTk4pXZZW>X< z<1p_$^YWYyHh7diLV@v09@fm%P-Y{3mIQ-Mnt0fIij!a*6GcjLz<6W0(6`-Y>BTV~ zww4NB0G{-SHBmd;V(fUfVbTonFlvc1I`aYF{LQ>N=2nrm_Lk?Fmjw4Opc*3hCqs@u zogvCDHLdpQcDkL&y?mMwfq165BVU7+&y#2PGISOV<%P#bca^x%_uIn$nhM0 z-rYwRzp?9-8LOm51i8YRl|L!$M->+=39baEi>f!Vu$_pxq8$f^5j5Q7H6x{aq4P>X ylN&+>%c05(kjA;tIb{Mq!Z6HElE9z3UbAD1OJ~?WigjaLjC)PJjWv{3u<#4hv4Y(I literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/build_nested_query-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/build_nested_query-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c3d190af9a737939f308379ef7ed8c59f04b1d40 GIT binary patch literal 270 zcmZwBy-Ncz7{~Dr5=#%aLJ_wUL>HU+>2iVwZa4>NryD|YdCms&a^?lO|K8MF9Upl3 z{JvM~6Kp?T{Q&Ud<_^=@tA4Am+j=LnHi|op2^Ig&7-jPfU2B!~}4T#)j?x$DS|- z#h9cu9m3;GHo||U5g_}?=^-wms7B#qXcw@mdSi86Zmf~Jeuj7H>b`nO_T&V#LT4hs zXravT8F=r}@hGI#9DCm35HlIL)E0jzrR}0F@18R+TzI(xRgs%lf2n!0?qQDlK<|WY IP$jGBFQYY6hX4Qo literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/cdesc-Utils.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/cdesc-Utils.ri new file mode 100644 index 0000000000000000000000000000000000000000..33f8dc808415fb6d86271e44d3b1c3e9c4c44270 GIT binary patch literal 991 zcmZ`&(QeZ)6zu~_vbO0aDky9cf_wnWvn`}dTPj6jXlfVn;0Mb|ZZ``j4z>e~ug6JR zr7P>B@3GH0_nzxlUWyj08<`{YO{$WKTUj&$$eepgFis5@+CfgdOoI86DORv2g!(FW zmZ3x!{o7lnel#^gmZ&MAG9H>lHB&|tM`G8*9vPu=wBZ7h;Jx74<)$aQY+8lSDs!-N zkHScn+|Wm01+N}7-6&a7!!iL>ZfGtmW2rUGK*--AJ_+$SBn}xT!9@WZ)(AtbCMz|C zDwhSQmNW^R?;ZK1ZZg4hTR3WfxG9?V4PDDh8&(-|%122si`UmzcQIYXmdeiJ!}D1n z^b8NfUC;O=@~z3pkKFu)DTgVZ_5x=&@$xGDdQaE!T`%$RP~zamiz3l^NJhjZuFWnN zOzXCD;t>~5+B%xmN*c%w6y0%JEB=caXb(x?^RDF__8!e!z)M$2Ybtu(o)%fdML{dj zmWKXpKs^oMSq~mmPYZyWmY^P5?k&&RQ2aDhk0-g4-$mUh-o~xFn781&|G_T<_XKp# z>OBi@s&3`^U)V0raCg2Bna2TGbehN7@4=!UF?%W-}QP kC*6H8yN?F`7=+d~J}xWb@zLIz^XhSX&Umg7^Sy+$f06`eu`Y2C|4qv8ybGN#-UQoMeW1DE;?NlZ`Gf z9L_!8@oWdn?W?K*Hp9L^*C}2u#YrBWb3{#hG%el}Aa7Y7-DS)$&h`L1C!~G&OC%)A zV4-~_MXlgwQWng7c?}T!zQ@7MV3BHOoGpoh+yBf*aJPo(jwGig$)oEn*4|k0jjN8? zZsj#+4oN~jVV*WZVjf*dQLUS)Y3&b5FQyuaI90uHv_r>O8Lb(Tk$72?1bMi7Mou-C)VmO4d5M~S q;y5l&^62W(k~b2ckKdj~O?nX~&yP#PnaS%Z_?=8A^p+~GG5!UDL}u~; literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_params_encoder-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_params_encoder-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..0d193461fb73b07850f2a0458f0c412cdfc1fe40 GIT binary patch literal 271 zcmZ|JJ4*vW6oz4oFf56nkRnLBX$785L?136Ph8(Z{}CwfF)!W#<#XKi_-O zGfK{6PX<^`MS7QU2E2 z4ui}5YJ_&t{daS%^lCFtdBqrnKcX()wBIQ; BT8RJv literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_params_encoder-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_params_encoder-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..122392bf145e3d2ae1af72a53ef0e68289fdfe21 GIT binary patch literal 272 zcmZ{eJ5R$f6ooq=w`$f(2z3h!Fi_98OOU`)hA<#HWw87TwXl67KZN@4ammbhkM23& zce6Rc?&B2|z)QFcCZAD{JG<`Ny*865F7sJL;S)DOp*E2Kd1HP1#A>R=1>lseOZWdg z9|>d7%tbn@5cUgb5b?Xr0F_$233&reS0Oo#E7*3Eb*69coRx=ZVI0a8@f;;Nl24!= zdYk##2yMex;!{M=vyjekoVdb}>ty26IQ*fMj;p?1KRjNmT~o!kf4=o(>UPn2$LNI{ IP#0(DFFjdV*8l(j literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_uri_parser%3d-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/default_uri_parser%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7259e5a724680df773803314b80c4873173a96c7 GIT binary patch literal 272 zcmZvWJ!``-6h$)>HN<2Kq@|lPv{@R>FBDv81s;T?}OQYi%RlBnHb@`yQ5y?fKyyc_tLHjoX%!*N zb59t9VocK64&iB1G{XO+5g_|guZK8?qRQwP+8Hb=W1X(cM`z{EOoCmy@?X6qd-4sm z!rn%H)CB$nWlx{ARc4;)fEH1PH5AIN!$%BwAsS$nlGy0(9-&d*Eju-Ad z_uOnwu={wW0pMl2bT*yI^gF+9>%Fl~WlS;$FJ~2^4Gh?uXzK@|f->p?a7rHI{XfMc z69TF^YxD!b-Ez>W@SSIX@|H(Cr43X~0jJonVB0v4wykf`>w{bPhkV692hEP`6L>?T zPx5S)@zYn7F3>2G(r6_)Ina~}GD>ZcemLj-s;$?LPuFQv73uAtYl&jmFFNlOMui=j HjF$fb8r4?8 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/escape-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/escape-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9e2e23a12d8bd35df10a0e9bfc3e6d7a0f9d5cca GIT binary patch literal 241 zcmXZWKTpFj5Qgy%$VAOr2?1MJV4DB%8 zTop&yeY~;-c$v;Er4#qv&RsWENzvj=0>qnYsyl@NdprXilk@T6e>@1Kpq#Vu&NAGu zP>bO^&j5>>N19RrWj$j^vD?759-OD9y7kWNht=HY3;7(3IEYV>HIFXo6JhVBuc(K> yqfTf%X&$uYDJ^8whCKgBDZ5Qm6_4@h@>`cn>Gm&hIhDOxd)_&W=v(fyC;1EI22B3| literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/normalize_params-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/normalize_params-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..86c0676c9f34faac44be851b2dc4b736bde92fea GIT binary patch literal 335 zcmZXQ!Arw17{xtEoEvzWh`2+j9u$V_`71&NE%Z>4=}tX_v`yErBwtBWW&ZW1?MXa7 zc;9=!_nppmu-v|23Gi%=nQ#qO`BI*x!KFc~xspGEwcK*u5g@Ng8r&sbRs0CBb5eD; z|7;OS5?Hi-p=610Glgf|9{Lu*H}zT=H-km&V_laMgwT^3oU_J3QM|<=5jh6D&_U z=|0}w>8xPO{K?deJ?g_2TxXhcDbKR#QXA}rl0U!);X1;|bDBj_Do`}yz*ym=vUmST z8% zrGmaWlzK-E(jw2O&<#a!9<`+(-a6_!pyQ`>FT)wpmj^shJISm;2hECX$UB=StyGXj z*Gg9Fc51ZtW1$sRM@F2OUOL`^XhNptEt;M?Q7Pc2<+af+6tTPlW%h9#mnT^?zxSvf aMs;!#mYN?23NWp&rj9SiLAR#y3gTY}SA7)# literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/parse_nested_query-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/parse_nested_query-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..46bd1000d27532420ccd837a5ca0053793c786d2 GIT binary patch literal 269 zcmZvWJx{|h6h%9rP&JH|D#R8f1Pk^2x&#R7|x4z%d#d?*Azs z3eKUNlCq{JxLXcd>A%wikl)gXF0P@h^EQTV1)F*>7MtqU8nqu5{yv@Y&t4UW;uBa+ zqlw~#QXBUb#NcTZQ7Vgq2GNs?85x8^OTUb=Bky;M(>wW5 K+Lm;($o>ElQduAX literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/parse_query-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/parse_query-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9202a82ff0e0ffdae26d0e04d9358357a40e776a GIT binary patch literal 310 zcmY+9u}i~17{wjrtgVPcQAEKK7hP=TFG~tGkf9>QP8p6bxl42Ok}qEFko@;vl10Y{ z@BR3_^VtEG`*$h;Hch{iwjz-&)kPZIv}iiXznwHa1GY`l;3+|a0(*diRl0lr+lW|_ zz@l}zRt3SsgxsMyxfa0lT`e0sgGKB|w#yj7S zdn`^YVqY+iOQmHR+-sGu%gJZ$2AwyPkBu;?{qgUdEfR!#=+DPv_%7ACuy4()=J(qu!BlT86)yMr2_C literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/sort_query_params-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Utils/sort_query_params-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..307e0b9df67bb0551db7cb543050521d5f99d887 GIT binary patch literal 270 zcmZXOF;BxV6ofkeupNTwsB5$I4&hD$Ta*m?Aot^d= LymB?_6NWB}g$rNwlnzT4V$Q{85d(WnU-un*Bxk3t32s|&y}Sr?!F=RFew$|-AS z4Z*{LwJLn)31F7t`*YJ*OdaQ`>mn|XA<-T8CQX^rnZG5ycE{`ZUFklk+rCDwBgN8b z3%_m;o&DGOSn$v#2UDIA{Lxb&G2;nISPWUpLLd{VNa;h5kUwNjLY5HVXsSq_0pXfx zNm^d(VCei5DqtEG0M~sXlLSJ|WkTfm9sZR)B}mA^5Hh?`lZY!k6|Lud8n8H-Z^nL*I?D+zfEYRoi`+i1Q#bhZ}GAAu&$RO{63_b2nD_Cgsu z-MQLA@mYBy$-fv%zK7=yT5Ii+!cx`if z8FL*>fkiwy%7TfKaiG~)Kp-apl4`7J7K}m2(?MC#C2w`;+^>-JQ5mTQ)ti%gw`!J; zES7zU1Cs+g;+qCUHcP^(lF7^t`|-bEeH11W0z?qAgdH_G{FRmG43lBMcgtpPq6-Db z?Abw&ZJ-3O6t=XqO5I^6?vFss2nw0yS_)azjqoJXSVAHv1kO_IC6u&+zj9QyN2Vas zjIa~QqoT7MCa^uCS=lTjo^Z{X;O`+K7-Xhdq8)O|RDzN)H;wY~jC|kwq4$iOP9Y(C zpnpX#O{XfD0Co-{3yJhf&h7GYvRz7iA(8$f#6qM-Nd4;)5u~6pj>@EZ8HHn{0gRm{k1kYC%7aV|7BL)BiC+IzJKQh`rR?=Xd??(D^ii3B!5?sGq%JHDG4A6U+Cwh;zL(8H$IP})%tla}1gPL=0 zUT|IV;^X{M$^SbRh#_|W4rX@;;@mxU-H{# zukD6{WyOBzt6^c)!5y+f zxn9ob0F_ZW-l!ZGu@~OCw^AiF&KrnKbnZ&3_zAAqe#>~iiI4kKMwXaX&8x?f5b%bB zG7E_JHVlh*8-FkPt;5AX6DTeXXWDh&%qN@Q;Y$_y6kWE3`guqReMGnD6Z(|)=`-rm y=akYHbcYVa^l89kvhEb=)$4@)&4$aEJ@K>PzTaoL&x literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/const_missing-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/const_missing-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c2c2e06cddb8fb64e70ae0d95239cb63dea73da6 GIT binary patch literal 248 zcmY+8F;BxV6ofkz(fV z?rQr1`}Y?b0G`98HTg_qzqi+t?*;gbP-Z6rT57;(f4!2kBdnhvUY(asJ8 zhZWdj{90y!LSMWIc?(rNW6Y`Fz)d|_XC%LKRv)Jo`V=)gu?|E{-ez?+I2LnKQzWl4 yYG)Kps)%!eC8dp{Zy`j#k-T~c=*{EryskRQZ~uOlpc(GhJ8u*{x|YVp8Sw)K7Eplz literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/default_adapter%3d-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/default_adapter%3d-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..313bb69b45f9b7c0e4c56a7766aa54cfd78f7ecb GIT binary patch literal 444 zcmZXQK}*9x5Jr2DwYK7=6%j?2h@h96iH&xa1GPtmr4OX|*Va^(1VwSPWpnfMnzJt(t2$;5`9l*(f zM}ifMt0oaVRd9ERoin{{Dgeu9N|a^@W4~hB)X`AE{r{VVjoxTh6~w!UY=^hSJ`3o& z%9z2L_DI@yqHVziQjIkl!{vq&kE}xH_VHLPRZ?PVxRSGObprepOm2U;#DVfg9h8L5 z(-KXiWlc?iRAPIC9!2bvVC3f(9Xb=ilh^#9WTumj0<{9 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/default_adapter-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/default_adapter-c.ri new file mode 100644 index 0000000..d853fdc --- /dev/null +++ b/.gems/doc/faraday-0.9.0/ri/Faraday/default_adapter-c.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"default_adapter:ETI"Faraday::default_adapter;FI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"NPublic: Gets or sets the Symbol key identifying a default Adapter to use ;TI")for the default Faraday::Connection.;T: +@fileI"lib/faraday.rb;T:0@omit_headings_from_table_of_contents_below0T@I" Faraday;FcRDoc::NormalModule0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/default_connection-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/default_connection-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..40a8b7dd0033060b7a8cc0b48ea6b9aaab01a027 GIT binary patch literal 501 zcmZvZy-&k16vP=&8fYbuK(G$vznZ1b*jQE-!R%x`p!j*& zdJ*(4z#%9E>cf9&9`>LpHx@ZrR!Shpt*qJ;2B^WJ_?B@lT<6kvLB6E}rU7Nr`nGB} zX|xAe_loK5i`3%ipw*|aDFay!Ja9nqP47I}2tc?1s2rJ2^KQBcHzjU28pWQqWDt?l zIG0LLe4%8z*V(jHMX@O*B!ys^)Ek%N)|3gbREfmo&4<9x>5^0^^Bt|?ONvK*yg#4w QakuSjlcW|VtCfg;0FcI|zW@LL literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/default_connection_options-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/default_connection_options-c.ri new file mode 100644 index 0000000..c23b771 --- /dev/null +++ b/.gems/doc/faraday-0.9.0/ri/Faraday/default_connection_options-c.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"default_connection_options:ETI"(Faraday::default_connection_options;FI"W;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"DPublic: Sets the default options used when calling Faraday#new.;T: +@fileI"lib/faraday.rb;T:0@omit_headings_from_table_of_contents_below0T@I" Faraday;FcRDoc::NormalModule0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/lib_path-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/lib_path-c.ri new file mode 100644 index 0000000..1ffedb5 --- /dev/null +++ b/.gems/doc/faraday-0.9.0/ri/Faraday/lib_path-c.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" lib_path:ETI"Faraday::lib_path;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"IPublic: Gets or sets the path that the Faraday libs are loaded from.;T: +@fileI"lib/faraday.rb;T:0@omit_headings_from_table_of_contents_below0T@I" Faraday;FcRDoc::NormalModule0 \ No newline at end of file diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/method_missing-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/method_missing-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..e9af07116435885f0285a4246ac923e37b1797f4 GIT binary patch literal 389 zcmZ9I!Arw16vjPBoI3E}K-3*V1yLEZ=j>nwE%Y!MGEY5(*EU_llDv|n)BX2m>n?hH z?|XdT_j|{KFE;vo!;-OAvz-gyV3m*LNfuq|{lK+!PMQ^APs%?pnq|K&OTA19qOYV7@2CJ5`j_4 z;<@gLrncB?ae`WU-Uz4yw&S%$%{>%KaIAMuK5#f*2!-Eq9Op+_bn{?9iwS)KyK)nH gUnnfsk2|;IBK&N4s2CP$dDTOIpw*z}SanLozf5L-g8%>k literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/new-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c8b40a01f2f8c8c5e78bc92231c0ddb85dfaf6b5 GIT binary patch literal 1362 zcmah}O-~y!5amz>S^`y7q#jy{VNnZ6X%fWEQA%1$#7d!xLg;nfyf^}RKLw-r)3?fTxUE>$$7 zGeX>5tI{2k^&}m07D)0o2cJ`QohF1>rZh%j*2sD%p~~p1my*1D7}K|G6GfA0rS<%( z;(JH^jEjITm|>K&pQwR?%?0zsCsGIu43na61q>f?e&JMH_n5#H*?Lj%c2mW{{XW8Q ziXamQryMSfVqyYgsu3;+Junhdd!#ODqA+525J?4;^E}m3iQiF;sbTSIuD-7DM~d3$ zI=~4P7N#YP5zIWLhBKHeDB2i2{LjzY;iY~Taj?fICtVS8ju3;2GtCT0wAU#)*uxewa&!)-oCUEiiIJH zyeFU&3|Pd15|x+bdpl&&?WG2nA#GwOg2vhzlGSF_T@HM(?XxOUfg+Hht@avcjZ7~j zlqp@pkI59RLgo5Y!WW>k;jj;Rz*7VVq^xv7P~H?4l)2s$t;^Xdb6s5YiW!od`w#RN9I-4>#Y}5BX6vJM3gTFU5CLxVRly6==knvvO zNu~JT*@eeJ#|fQa`>+T({vTxxN>AFK;Fmp55bWvj_foFvE@&F#(rx2DedfQ#{!MwU z0B*xS^F8R(?f^}ygj>oY4IxXf0C~}g7)RfG&DnU~DmBg)t=W+=Gb1+=cH8wRQZgPH zI_5Z%(a5fovCotqjgiaSX0v&<;(OcsZid?+7_XI9=bs0eSx5FQtQKPIMK^epKWyLJ MM)PwSrW~7p0IukvhyVZp literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/require_lib-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/require_lib-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..029d823079eeeefd7eb102c9e84e5da4a5047891 GIT binary patch literal 245 zcmYk$F>k^!5Qbp}WDsGf1QM#)GPNCw=VJ*{8!1B=P&#F>?BoI#PA+w9A^ttC(t-6p z-J^Fp|AF=Ciz--YcUk zg6)Xq(q4TJ5MhLEbeZ`Dqo~vjTWRt#;yqvew;s5RIi) zIH?Q@YD7hy3)mnO8oF`L%Sje5-#!8~y#M_tQOI2WXNE&sZN{D>*;bmIYHyG~0HBXf A$p8QV literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/require_libs-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/require_libs-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..945836e152644af129df4e14ff15c6d54564c505 GIT binary patch literal 502 zcmZXR&riZI6vsK3iGW6<#6&$bJE@7d#9McnL`jy28pP8MOE(_S(DlvNPQ!n1fkh== z+xI@-A8)7m&QC@Um~(!wmqV~~oFpf5H};PRJ}OC&Dw!FNdyj+IKN|=V6S3rc>ofEQ zW8N;SOvxPi`35%>w5UqX9lI((+a_;Er66mP7V?YjnOBFMktpY0xR-dbe-~>Dq=n*a zv~gjWte;rzfjM6!NP_8kp*Q}=>?@%cPf|kz!&c4hU$4Tj8}_1sA+Z7p7=aR2egb>5 zB=wAGQGj6L;Xp~XA|IBoxZagq*^Dx`2NFj8tNIwSGvXpRgx@>}6&3fYe(3Bjs58rTQB@}$6*)YvUDIIK2L_-oo-lx=WqA`ug$aIyG zJm3)-8w)<9ChBc_Y^>ZcFZ!lPPNa68X)gY#*)c^u5PN3A?EYW3G|EnTel`wuK+*Cq l_nY45wK5W`tibC_fC3J%3s%<#;JZ(+N4frr=&^S9CYX0=koX=?R!eBG&jW(xVCq17L zG)B~D=FqgJ(Uw40;AX-?y)XnmavGS|2cev1fWK~v84C3hf~}NIgaU0!G9kMmQ)yF! z_5nJfl?AN=oJ>unKu2K6w$fR+7G6wwMS=xi6zJBBzm=%2J_tn{dbAbH_fq!gq{F(A zWCJ4EUTer#GPxJ8`#yb`vhl%D6dlEfQK;kwZo6Awu{Xf95f?(CmERT-%0nP z`%U=zuQu)X7Jb9lC>JjH!z2s~UA*e8UyPk^f@Eof{VG~bc;}2}UW literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/cache.ri b/.gems/doc/faraday-0.9.0/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..c5c85c710b232a6bf9afcf5d712687004857d9b1 GIT binary patch literal 13317 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 M{jc)advkj7U-FJUX#fBK literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/Base64/cdesc-Base64.ri b/.gems/doc/http-0.6.2/ri/Base64/cdesc-Base64.ri new file mode 100644 index 0000000000000000000000000000000000000000..bb0f8db152a42367647c036dcf54661036733d53 GIT binary patch literal 353 zcmXv~Jx{|h5Y2!b)1)jN7?{WppcxRud5QRvB2fltCl8V1y40$ZvuvmE^KsfnCq3Qi z-MzbaS9AlnU#};tV(g09DEr`A!pIuR3OgN|y%Jm9|M+I- zuxo;7jcRb$NbEyg;hR<&{4Lpa$z~-_PLcAoE@sjQ??)w0c?y{wTBBv;Q@F7XgOWjQ zPi1bMK8m2mqAupT_d)bhO`|Lu36`I59x>r$Gg*Ea&-e=f-%(Fvwz$?WAQQsq@H N7v~?X(SE3-GXFblX2}2m literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BasicAuth/cdesc-BasicAuth.ri b/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BasicAuth/cdesc-BasicAuth.ri new file mode 100644 index 0000000000000000000000000000000000000000..f39e285d7a1a92af43d826d6fa14f412ee4b8b0d GIT binary patch literal 638 zcmb7?J#X7E5QaSzwBWBH1(KmbAZTiUz*0LTz-duFYD7btAh9P60!336TS^qjQyk>i zmy{FK89EdMNRaRGo_l%x6&YRzp*i~q2v4F7iUOfvQ+S82e_m9ch>?~T37Q1Js2k~)o3!J z;-MFNc7@}Qu@6+!jizlytUOGEuRX`7`z82QUxQzCLfTq<2Tg;s#BlCch%JO6DkaTa za4hFaZ^8;|8S0XKKmT^&qG6PjLh>|-q$sS4ZTNwZ?+9Vx9wc|tTo?VtC{eY*UKh>A z1x&cnW2iq?=}OlUa5*6#ez?wjv51 zXWn}=@4e&j4Ti7JQ~^A6A4_f<+7v@^lEq=icL4;mJd4MRJYP9N?@%p1(F*Do95-A8 zJfabmM*zHF8q9MTsJ@h$`O8_M#;r!x1k=+Z z%;GE0#5O8MHMdo>j!0P(xj)WVl)AxrIqZs&C1%zU^oHwi#_j(Mg~s?3aF*6W@+?lI zC?}1zYJ$H*vSy!hQu>h0Lt|a;g-J@SuzOr|Tf=HiEwflk&ZuS;b=KuHtmKk*Ns<&t iSvCjHLorYJ-m=^Q9eoMF!=&xNrt}w literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BearerToken/cdesc-BearerToken.ri b/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BearerToken/cdesc-BearerToken.ri new file mode 100644 index 0000000000000000000000000000000000000000..c97a82f50c3d71deb035ac6bc6d48de9f5464f16 GIT binary patch literal 738 zcmb7?(QDN(6vq1?xpjA&f-oNx34If#Edw_=eW{y{6`UJ-hYx)yX?uDbZ<>@ey%Ya> zlXinU!3PNh!a1DpcfNd2{98Es_DNL$UzP5dI2UXf@)z9Cg6C(*H0qVwpd>&(Uu40% z%hl=z;NxgorTK4WxRRI1YSaL`-3hVH%j@zdR)!>GrQp>pa>ev!>;bIe*r7B&EYqH8 zGvq`i3qSF5U%~6gy*Es=wPt-wY68mR?J{c ze{dmaiBw~!wn(|8+c-Q8r)jX4He6s991C7rEz?Jjc#D}gDksB>X`@h=4g}&x}VwG%gOCSEY95; ozYM^4JI`h+_qi9}2g18wilj$b@aCTZv^p2n%iSnnsd^On2T@$-@&Et; literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BearerToken/new-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/BearerToken/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..4072fb91fecfe174ecd1039f282ebd2a59420fc2 GIT binary patch literal 443 zcmY+AF;BxV5QP~~2z2RCF#tnImv*5M1H*L*1*&E!s!*7s%5suRW7Y9Rj-v{GJxFoR?FXzaDNFrAjLX}aD z-lX8N!Ks&Htuf;U^KLcVgoTh8`Oi|Mv(lJ)#!ut3vd=$D`}nLs_@vWb8iZ5{(-T7N z8dhkknBl2JMg_}A8QVa^Qj~NEf*`qw{K2FPHSOf#a2ff-lUnU?ncW^c`XpU(`6hYO F1b@BKk|h8D literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/build-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/build-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c2cf910194dab056cbb1414155b5b4134b9ccbb4 GIT binary patch literal 463 zcmY+AO-sW-7=%4Y?8m84QLKk0A}C0k^Y#*@mgZ0`8c(5wO|orPH+jSEyO#Rv-6R$4 zb!M0up3}|;9lp&VrS!4fFFEFrMMH5GxV^*(nK{&Xo(JyjA`DkHVyv&k4?_Xvg0qY( zO55DjnTNDrnM8^d=%}q+GWBIDN^QR>c!?d__baAQM-I^IuIoP9^EX0r%R-7|k|S0V_8&*wUK^{VNqasN0vpjb z=y;=`h><0d$FPZ0DADrJal$3+JkN_x0(Wp%|9fbj+}9=kz@ooA0?#+?aG-{ literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/cdesc-AuthorizationHeader.ri b/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/cdesc-AuthorizationHeader.ri new file mode 100644 index 0000000000000000000000000000000000000000..06dbdfd93ab562f630261a5db867f6f537adb57f GIT binary patch literal 690 zcma)4&r8EF6z)OVxL*hZ6%-i(!ILWtQld;s&A; zc#ypJzVCZq-VvCivzJGeBJ`|u&g4WbYRO4ofEb?N*Ctb1d@v(aG3IQ+wU7L#Q4Fuf zv)L4(p9-))3KhE8f=-xT*Cj%hq0V_>0BT1i)21Ro;Q(Mje1$F#Yo|=Jm1bq;yL1e1 z4p;_RqhqjPvgU)N7SgJ!eC*FqD_RQ4V|Xn^GR%xAhircUy6wExNmCt0Di@}C6ve8d zORaKhSRy%9OPZ>}SiKcZxKwZ9POOJpF${l&A1164DRs;{Cfq(~zx$(|GtD(MYR!vp z0Ne^K4Dp&1kRXPwRI;j>n*b7^c3CG>4zR2FN>s*vvF(eX#q5<@ z8J-%xu(Sc{lv-?<;qGF~MNt`6q}-Y5B;bxq;BFIpHhRRLf9=78v-8~`^lI_!G7%uW YJy)9HKy(uIqth53yXA5!(jQjy6Y;0k9{>OV literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/register-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/AuthorizationHeader/register-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..1cf65da32e52c749ffbceeb72431f2b6fc252fac GIT binary patch literal 444 zcmZut&r8EF81*1^b9hh(it`XE!UWlR&MqD5SPzpS^;AYl+pG;s`<3L&#{BC|R}}?M zfxKVed&ix3+JAe7l+tOnUvMlSi~8auaL*Lag+{I%>b%SXcQ_BjrDYjQQR0K4fNIWJ z#ucSM)QK|-X|Fbk6e-X_YrJ4;V`@rmiYa-89oqA2rcg%?(A&S9B~vU{tS+2MH|pBd zsn(DRhMeHO=42KV%XGqY!7*8T>Nu8^7TLST5y(LwKKhfDw$kBW+eAM E0b9V5G5`Po literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/accept-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/accept-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2546b203caba6f92cb8fcc1c4164873319ce44cb GIT binary patch literal 317 zcmY+9F;BxV6oeU&DOBoI35ha9VJQpE{IaBiMr24;p)h5z9LI?*9NThUK>hcmDIhW5 z>AvqSXYa6ld$Al~YmT`I2R5HkX@REtJk7906a^k46C$w_(@}urZ9Iy zr4_fZIxpqSe+&*_oE7!+iFN--Vp70O(kLym@J_30BN5$(|7tz?YN|wu?G#ceSglOk)5hD5;z^v^hH`6g q)aq#^wEc>rsJs~eu1}1KkSxZ>i@&eqV#;sN+I#CergK{lT14M@X=KI# literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/auth-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/auth-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6ae6e5fb7b5c552a99614dc2ad0a34f89966bba8 GIT binary patch literal 335 zcmY+A%}c{T5XC*n+FI$UAbuQ{cu@~FH(`27QG+=|iqumMVUljMOE)`lGqLDjZ)#ES zI`iJ+_uk>)4JNOTR07Q1XR27!Dw~+2Bp71HT7Y3Y{*HiaHYJMi6tCIYhzUsoLf^&HFGm9e@X9r@goT%stxBm zlW|p>uRYZ{@4Do)&P#IKv$lDmEN#Ou%np*^{MWxf#pUU~%nSJ% KZAz=os_+}qV{B0X literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/branch-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/branch-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7d7e8f536df41d9e56871e0dd6fb80daf52529c9 GIT binary patch literal 254 zcmX}mF;BxV5QgCn$W#P%s)R(hu)xxKzAiyPM1~-Q(kX*wI}WyRe3o+o@$X4hV7-%` z?>$={VEy)p8sI*B*M=;1?b@AJd8U#K+A?5IWtDH9o8}eZ!AcjT^5*9EyJuwymod3d zNd{qaqH38wrU)>*(_jKEAuFOxG`0)4D0=5jm0x?Oc9tma^dGuSitSkgyuiVcuts(+ zypN(!I0!n<3haf(K(jdtWjuay&f7(muWm7t!!X_*g(91iSO2l|snl1ev=>Z+^fh*q GH~a_OVo|*S literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/cdesc-Chainable.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/cdesc-Chainable.ri new file mode 100644 index 0000000000000000000000000000000000000000..cee866a9a007ec41c4c1dea3fad420a4c8c7e468 GIT binary patch literal 907 zcmZ`&%Wl*#6rBZ1oX1ok3Y9=&kq@9*J3@+7T9HK&g6YbO$Z?#BRVOyiP0QzFrwNJL zL0;W^?&J9Q_!YXt7eBu$hVgf0Ix25fJxWgA3REO#S1lDitt9ubcYRYN=id&89~iIc z%)3by{`fTDmYVxfV{E659q$3*DA&}$Ks=TCC_`k2!@Loa7s&@Hs>>EYU$SM#XH$8Z zcfe_`Iss+NX)XHWP&P(&B{&wPYD%Vhu(OA<;!-`PS&(L7N_NxniC-iklXMu|B!Y;K zBRy79FpK;6OdAE90k5Yp)yGj7LiX5h$v%RgH2ln{?FT$26Tkh z73PTxV@tNT`_|0+nm2TmP%U^wkI z8=y66Ji3X8C!Iqubb7a$F?tYmtq&f>^eA)jYZsRP?lfoLOxb7RX0fwIwkO`?gUVQY rEEm}k?`|>vmGk5u!1$MaY%4TDVwWzKpB?Jud+QJPe;hM*;?MmBY8L+* literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/connect-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/connect-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..251677a36dee020ad2d00c66a3e4458414f11a2e GIT binary patch literal 341 zcmY+AK}*9x5QRO+TCMa{P_&07UKGXVJVl5^gE>@!#8VDov)ML_o1L(kC?fuMx0VWC zXWsjG@9mFXVfylb65!r`E)_Lc7gK$Z2FDVuRgxI6$0QAAPkEjJ#EsBaR7PFw-V2r_ zFz$xRXo+yXWi5q!8#(|F9$IB-1mma^j{1Tj%>HXK;l$dBu3?MAf~CQAjP_kQ;)Gmq za>DlB>LEOjvw50v8hkLr7A%LOXr+xxgEOP6c|+9Ae$ZCKI74>9?hz@HL%vMuwB Mt`%m9^OsA@oZk>CYO#lkNImrsk~CezUh_(tApZAu40rPS zczl1K`SJ_apD&~Vp4?AqLPt%#wu>U&G^UjigU}LDNqra}8L-#9NN?Y&>I2}plh#Rv z=H{Qz9m{h_hN#eLg6q>lDg7Z10MlITjSEXivO)SV)-$-sT8pMguh6P(7s9aBfBgrq z*p5}eGwN*+oso@o`%$!>dJ&ESL9Ni_!qgmvGDzQ?^LkdKtGl!Q{@BQp$$xp4Pp4dO PPPljSy~L85h=%_Hk)>Ny literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/default_callbacks-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/default_callbacks-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..bababd3b38e977fd9fae04602e33761f165a7dad GIT binary patch literal 268 zcmZXO!Arw17{zxO*|4zFa4>HbL@zGqZtUaRUI;Hi_=NrmS2 ze{s+99Fid_w3^`N!Y`#i#Q|VCi@kAS2}w3cAI5qHS6OS(6zLYN+I1leJN=7)^os3S z1w5nP2GJSWSob-K)>ALSSwK)LG`TP_N1+VT7w5d573t#s;XKWf$$ItYJ4LzPT%6v> L_YzBLA{zb!t_W8z literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/default_headers%3d-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/default_headers%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6c26ed1571153b8112450956e7b819da5276df87 GIT binary patch literal 273 zcmZY3u}j1-6vy!!Bpw!SIuUfM2;Smleuq#|iybO*)Tu*A(pMWy^Gcc^{`dB%=i>T! ze1D&ltTrZ{nj03y0^ ze(!g&`GoZ2nKZz`{ZtrwYMa!o%PeiNlhFpzqioSn4A@IiX4}`geg}B!rEyYOygRS$ zSy4bTMrDmAxLw$l^v5^?%tvuR7dDXOqx4~FR&bej#$uV>Sfh4*2;)xw!5_V1dsYL_ zX)ue4abJ_@JPjh8?ge#1lM6F*5(+JSbIzMpnXT_1PSZS@ov;3F=cv%vi_;tVLE4Ji HXp#Q{AoEqD literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/default_options%3d-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/default_options%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8a2f02531e39d6607714675891300ccd5fec7068 GIT binary patch literal 270 zcmZXOO-sZu6h&ttaj-C}5kYqqK{rm;ZxAYKv5Sffb=5^k($ogiypRvXe{Y7t*|@#j zd+s?|e!zP7j1u6{{ZZJT?Yeh>r-^IJg;Cf4 zdRtQ0P`D(FmIzk|ddvM+asc@%&C13l6qVyXhJFEO)u@eX%1figW{S~mrLv zt18GsQqF3G>l3??@iPU0Zym2rs*0?^Fo>+L;ToS*`#cJ0>-&mALx(CM3%s zFuqojBh2@tg4uU(07k6ug?1ANQp2npDuQtNKeJ+%tt~ShNscR$N2kkOZOB3^2K1H- zl8_Qk(pD;wM;A)gi_ST-;J+$&w%$eJ6np7tCs-r(dZ4Yvp1Q3p#g=l^Zd4g)Efjvl vaaB#D^Bw2L)EL_M!D+ctIi}67L zM@b`<$f7ePt7Ye$S@NC4t*w41ae}>cv=gkBx*cd^v8Qg*q}Wi7+KnCqt%SmlIF8G` qvFFNLc@v^>67>+?gIJ1S#TwH)&CD z``+c;a}OtPu-H6d3Gk@433n}4*+Lw}-n8YcB0!#_*gJbk(>1`VWkRt+@~ho1AW;M} z-4{}n2p4-w!pwWG0S08>apfj33pF#&W(48#e`d`LYYfvZ38oo|z3UDC=(%;2(S|!} znX=Syt5I1_3#_&zASoP&wU9ja&ZQ`pt#f)={(9Y;Vi)m4?1allOQ9N@*9N=XjpjMl zd5OvmW;QRl#82P%vxC?>z3Gj(qo|!2>gWUg`o0}m;e6OX|64wsqVi-v;}uQEWP(*M Gx&H&D&1sbY literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/options-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/options-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c85bd33ba4695d07b963b40814327db1c677cc51 GIT binary patch literal 348 zcmY+A!Arw17{xtEoKAKcD7r(a7X@*}<2QuLw3x$WlP- zzW4a?-a8zuV4OT*3Gk>t7sAz8Wn+27f>Sh3qHYP0=a>bPmo!}h%xf++FO<02+cOf! zFf_hUvP8J-SqpC8yaDLIz7g6DU>F&0U7Hbv$^XofTfVW})MR#?5f5Lo5=Leug_CG4m0-bzlEt)k&P>aF&pTV}B4LD$ba^d!CH1Dw z*A|=HZI|S@&P&v;tJ&s-Q1}ssVRpcR^J{PAE&UxzAL!Tj&6X97x<5vLPjpgTp7onv M(KcKyu<}ZTKSXbFLI3~& literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/patch-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/patch-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..bc5339756faec7849cb448e8b0d71bd0a8b6c256 GIT binary patch literal 340 zcmY+AK}*9x5QRO+T3hI;ps0r>UKFIwd4iCl26KoMiKiUGWV2}&H<@L#L5ld_O$-WN zXCCi;?;X$HVDfM+sJBA0fTb`GE2ZUtr&Y13oiiKpOSrbhkHinDQ7*3~ma5%%d1a}| z-Pj?gDi_qc0kO*qsp-S_{p=|A&To3F?l_q#_MU%!-Hu-2a#&*dx503V#M#v6g=~X5 Jp|aP~{{}4rZb$$C literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/post-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/post-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f88f9e02d757166cc057fc9c5280f4862f711115 GIT binary patch literal 315 zcmY+9&r8EF7=}Ga+#KvQn7js5%GVw+feZO zeJ{`ZyoZxFSiC->0Jt}wYZ*Fhs)ahrqp3w72#}{Nk4~S)&l4(WqXjzPvG$7^FNsogQ zk|d;r5`U>$zTIGiVwA0Qc}@r2qf` literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/put-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/put-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b2e24f7a1cc32e238024965c48e5c4dff12f27d2 GIT binary patch literal 312 zcmY+9K}*Ci5Jo*ntS;!RR! zKHj{yAHBljWsL&h-h6DN@35&B>L8CJ8$1E>nC0>5Q&|=O4;@#A*IHgqrxnREnAuQk zB@oVcj16~h!2*oH&`aYZn5C9GKU4(a;{T@Lj&B{e9a$Y#B#)1a;HgK-sgnZ+C*=5} zgrl@oTITVYR`s&;-Y&(j$E~Y>CP|9D@~o4*QD!@^)?v^5WXiB*0*xP423AXr?@5wW rdt=g7aO#Gl^$N{E@95{(^~6f&WAFU0bgC35JMU+7J=Ys-f|kiQfYf7K literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/request-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1f0912f0862b048a666668d5a068d9c040216153 GIT binary patch literal 349 zcmY+AK}*9x5QRO+TCMa{5VXh=FACM>JVl69gE>Ts#8VDolTN!!H#>2&X%X?io6uJ9 zI`eqnd+)gS0mJuaDgd6$SBy^5A|0xe$UC?A*kCIbE=#oQ}aju{d3nrgF!pU;BSid6c!h| OQg38Sp<`M!8vS1x@^H}r literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/stream-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/stream-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d1bab5d6c410e953f70c2e5f7ef736ee0d3e1639 GIT binary patch literal 316 zcmY+9K}*9h7=}GaHZANl5S)im5$479{PohImi15>QcpdEG)?}4aG7;Viz2?(s#(hr?3(|UJ-FtGBpLQ9P$^ie%-++^VNb(%JH?K2 rG+`|Bv=JH)Ns`oOMLby@?b&QRJo~#k+H!t%s(wM&GhJdkXpwvY=x$|T literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/through-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/through-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6ba65b71585553411b45ccf81106e9bd5ceb873f GIT binary patch literal 254 zcmX}mF;BxV6a?T7C{&~{RYC$Lvj7A2{JI1I5gvjn6s8Q8ojA3H<7YXxp#Q$9s*KRe41=&0 IcF8Kb2PA?~)c^nh literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/trace-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/trace-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a32f3c683e56316d71560a3359b494f08ecacfad GIT binary patch literal 334 zcmY+AK}*9x5QRO+T3hI;ps0r>UMh&qd4dqp26KoMiKiUGX0z!o-DKisf)w$;n;I0n zzIl9nZ;mH#uy}n!3GmSD6Ga-!Y++7fZ%R%`#el7&*t>X6(+$9*7N!w}RoCM&U{M6K zwlA!a2$v%#5pLJF00XqIRYMb)g{^SZWenl!e`h0{*gDZ_7Mx}*_Lgg@k&{;3srO!W z#0w#JoW@LAGw@izQkaI7v1$;rrdVmBb|rt^?p*Ox@k6W)~pMg zi46^~E-#eD58wB*qu4uN_RidLY{_8L@q7OHb#q{a^Wg{czx6{D$+L0E3%Xj^1k2tk F{~PpOYgGUM literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/via-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/via-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1e98e90a56e97a52fce5f610295f3b0d35e5eaeb GIT binary patch literal 351 zcmY+AK~IA~5QROM6{T`&qEQb7FV=(QJX|m;kpreNc;Y|?y6tYdFt{vg|Gi7ACSK=F z-uvD=blzb4`bagveY?%L5wt9(@+b|Q4~Y!eQ<4Vf&w0K8cn~OCtQ5Z)VS8z2^Jj}EDdHEZn%%W=I;aVjc?x_w P_Vr#!H>fgN4vL506|-#= literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/with-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/with-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3d77a394ef0568adeb9540067c4cb59e3b784337 GIT binary patch literal 249 zcmX}mF;BxV5Cz~4m0O6^sS*OVu)sn+UzZ>tB0~^DVaj0Hj)Sc_zR0<#;@^|Bg7w|$ zdvCe^g6-!EYJjKkQyQ|^)LXYI(u<=b%YeOBMSA^KRUZJ)R=OaSH+QGop5-|t{iwXt z2)AdYl<_e3024WOCeRv^te267dI6VN>%1w_8}HQ467@U%Cq72S_N)S)VdqF#BO4dK z2hm3C1kIfSTcI(~WDY_Zk4MgVy(rSn{rqj>@GuKml26h9(kaUI)p^=G#!mVYo6#Ho E3mN23wg3PC literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/with_follow-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/with_follow-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..28edbaeef5b577a765c5b7db88dbed692fea676c GIT binary patch literal 337 zcmY+9K}*9x6ofs8V=xupgZP=nuLY8#jSzXoPib#t82IcXq;xy%k2X&1u#HTrFEfZ!r?A zJhovy!YnM&SS*CYa!BATtdz#sztJjROXtkG_`$ok`FAAVO C+iR!* literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Chainable/with_headers-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Chainable/with_headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2e14459bc20c0d2fc2a851e26bea7dac1c444f19 GIT binary patch literal 368 zcmY+AK~IA~5QROMm5L!TX=0)tR=lVO%Xzq9tV9l&#^8wqSzzdHy0Ew`HvW4TYfXBc zc{A^O@7Vc(`TJ5;08ia_iiWE?pNo^kKi>+&3y!QtJrE!-apK>+X4wkhnKRL`QsV7_ zCM0nTZasy*bRF3BVbBGn4>n@Du)p=h*f z3p2$iR8v%{GZt?sN|b6F1VK)6+rn(}oX%C~IF{-tbR#c33liVE`}4n_){$rH@&1dk Tqqw@*rF&DlWinOuC^7f}>Y#L9 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/cdesc-Client.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/cdesc-Client.ri new file mode 100644 index 0000000000000000000000000000000000000000..9f6457bb282ed176b1cf30b0876b7834bec292f4 GIT binary patch literal 897 zcmZ`&O>@&Q5Y2&c+$5xATG9gylkpFrKFb#mAsKWibkg*K4jS2(8&TOZlH3Bno?XWw zEet1*-tNBrc+W4wTQc8#G&v!kjje=UYT+C^Qz4DUORZ$>0}`y(G@5Jo~*s69JX0~)>haJycwHvEQuT>%v^ynA|GLjH=!@t@lz zC;gG;v~F6z$l9`$cHz`7i9;o$bOzI>vvipMt1E5=!cLbvp=w+oOM2?Tp>)oMY)GR~ zj!wV?7P4V7fl@%jT0SC{LKc}e)_5?0EZ6{^lg6qC;Uzw3^ip*j=UtDU0*GidX{0T| zYe2I`8aRgqVbCN>=p#Dmg+Cz46p52lHo}_oQq{`s_`wK=EE>(xHGp@n;h8CZ9%HYc z#agS5p(zf*D`Rosey}NMWB?||31SZnWEM5HwkkBga7~l literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/default_options-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/default_options-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d4390879331230d5fe2771ec20f2345b04ea6cd8 GIT binary patch literal 249 zcmZ9GF;BxV5Jnl0712t7gv!vVW~Z62OHfNx4@Ia7QwPg-9cppOS@uQzeWG@$*uU?+ zcUyeH{eD9Z;Eg#Q9zvny)6utPK-LsFP@e^e_eROZwrM^A));)xFaI|yQ7b9-VkH`w z#KB^41oI1eXVT9Q0Y=ZzjpqU;RWyn7;Rf!iHlSDX8G~J(nB&r&1+U4TS!G3CV14rD v82az5+eDpaW6^7BwWFR#VAj?n{g!n#Rr2w=b7a(RcFFjl)EQi($+`Rkkv~xr literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/finish_response-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/finish_response-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a921f206b36c7537977b2fdb069e279df2bc77f2 GIT binary patch literal 346 zcmZ9IF;BxV5QQ0#TPR|RV1U7d0a$3}>k?ENk)fzUWy)Y(l1pvXu_N1U#lI&dEHK{P zdw1Wx)A1)nAFs9ocrjl~3ewg^q(*rhHOeS2g(Kftn_y09B zmSu3!Ikm??7H)>kOLW^^2hg9{wY_Z&le9w@e8DW-{?)9|;l^Pn+3c)fc?@&Zy2NVB z8|(N%lHmt>*b{ezm86;nNt{g0ZNsr|{=&}K8qU*3Y0Bekt;(qkp_^7e)X%PD$9a<4 zRs|smYh^ZGG|sjnV5v#iMpV{>p4E$zv^^wAQk>-R=<(@jO)vW-CPM~&omE%E6Ytiw KsOK8JPrdm;XB@yVZna~d34-gtnuT_H?Q~m->1ig?@NVX? z%aUB7`~{Ldkfi(r3zkgMV^fN$Si)JnG8WVD(wclyF}IUq5BlKp{XUARHmoYtrD@h) ztsK>gb#777N)^;_2j^9emcFAX%8t@7xS^K)z3e^c{B55TUvy0j4;^%KQj88SyppT6 JomuUD^aIE%a#H{R literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/make_request_uri-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/make_request_uri-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..03f74ac7e983bb92d80af2e73556af5f04bfff50 GIT binary patch literal 336 zcmZXPJ5R$f6ona(DHO3#V1OYC3rL7&zFmR}5gCFi6s8Q8liVa${la!Y{r8w=LX21U zJic={`+&v!vu*&M)UH53=(bw$qddNlY>U+5=ZMbJ(Q*RhCClUZwJbLPYr#?Z+kc`J z$uc-KmVYsi8m_18g4yk807B6ygKq}&)G+H^MKs*})ohq$y=7(~tK*72k*_Y+2cLhdjC&SExD%yvX-mf(avf~J*x#$ z-O)xXADA4iQRwd^NveZ9KEDf-A0ll$*UH`h#-wLq{(Kr9?yR|-z~8i$OsoZSF8KjE Cv2F$c literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/new-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..dab7093c91686ca5767cd6c236894e62826a4111 GIT binary patch literal 251 zcmXBOF-ycS7{>7%q!zm#=WxrBNf$5kD?;V;FvE#RoH~RgO>HpE8kK2;&Z>Q%bJ**D?k=hc<3MX1Y!-{{Wr7P-FlA literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/perform-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/perform-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1f4ba92937394acd122758fbbde8e961c9963185 GIT binary patch literal 329 zcmY+A&r8EF6vsVCoL0Oz6wyPdmkng=`R!8KEcP%dQcpdEv`g1unirE4@xM1)@!;|C zeSE$@PA4BQecxaM@T`Bf!gsin$3JaFvJ4_K z)Jir8_akV_?dMopwc=|K&XW}>;UaCN5_x>9WWDUXH_PT2aAE7Co}}1I&pN?(f#z6iv1gvw zN-%6$gW89Dj@2UIlO(B5^7wid44x<&FHyVs0h3;Z0iv;bxU=SFEb$iR;cBh8bIC6* Cb!ol; literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/read_more-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/read_more-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4626461bc2ba55287e0d8851c39a89aa263f5d8f GIT binary patch literal 317 zcmY+9F;BxV5QQ0#DFk(@U?@WrgaixCd|iSH5gCdq6s8Q;CAl;fPA;-t5dHPI&43tB z@7|~HolZVr_WsNjz*GOTCf9OZ%+y&HO$}i!J2oUhyrfw)f6em^z)CCX-R)nx6ln^V zgHd1Th+#g`)@VL=1As^GI$xMTkPK*?Ed;~O|DO#S+!`EOu{Sgu- literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/readpartial-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/readpartial-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..47b6a95fc151835befd064a3ea181f41380e5155 GIT binary patch literal 326 zcmY+9!Arw17{xtEoEF5xP(+1LFM4r3e?zFw278!{+Fk4+q;0x{rAqU3t5SgAPG4Xt$N zd>u3$!~~_;$tgb2jM&d^pF?v`D0bB0G3LM-e3OyQk3Tq znSm+EHOxj(N$qwp0D(GmAw7X8Gt_!lBMle-Gb?K8#!}Ow^sq*urlebeX^(ex_^+md zqpXoi6!DpoY|(me7W~KM#xj(m3X)8B(vw!uwd^;JG*)-SQ>Fyb4dJ@?LB$a!lzvZ= wq~0sy+0~n{Y>o#j=U5x>@GbuQy58Zkldw4&*M>Xir=$0iwjEVVMV(8&0fVY!Z2$lO literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Client/start_tls-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Client/start_tls-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..563dbaf8195d3a7ec3e8931c38c55e1261b11f1d GIT binary patch literal 321 zcmY+9F;BxV5Jnl0DHL_8%20%&uz-YU=Iatvh=@c{1!2lyIj+-Kb$pS11;MY!Z3e`6 z`tIJn?|AS5%HqMo7-bNk#WIU;-t&A7aDp&$$lb=$rlO|0 zV7Y?FlhlfuuTBFv-LB@1jbNB+YHUl8!eN9Xcf-^Fw`*$X-cWr&o_6wYyx~T$XWqNO zD2GA16Ow1~RElzTuvX7{u6;2j@_dr2TG-;iX(gI{TkMRg3rkDM3$-hlYOM3p7A2SJ znBYNzhY1P#6Oz#F%lz(Mi9{rXq3%j4nBzm3XrnA=mREf{(nfq!%YBo@W6`uO3dS#^ zc;pE@?(4+WfS~Oqo4L2~V*xf!PpF1OB1q1u1ZPtyz0KllpSY7;vgzLsTB)j&{1*)a BfkyxU literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Headers/Mixin/cdesc-Mixin.ri b/.gems/doc/http-0.6.2/ri/HTTP/Headers/Mixin/cdesc-Mixin.ri new file mode 100644 index 0000000000000000000000000000000000000000..21b7ffeb5815863188679246fa9bd3bb1a9c9659 GIT binary patch literal 491 zcmaKpK}*9h6o7Y-H0xH835p0F@&jDYFPFl!tcQur?UX}F+sp;irlhIc&o@~e>O}&9 zmzVcFzV|Nh7H-#1x&(O9rsis;t6m9qEpbM|l|0G@0eVg|a<|-UUICVZSHg4vLyn>} z)^I-%R@{8_Er7%IwP-AcNz!s-JBBn3FvV;HVX~7-WaL4~V!pSwo$m+Yy!Oo=O@S!d zK%D4W+T7=4^WNnbbN*`i6j%gS(#KMeBzj2{60SlaZsd(4AA6~!K4H-rGW{k8S-v01T9aCTrTR=~9B zw6i6`+d$?je0L2%?|0tR6u~rYRG{`Wf=OCgX9RzDR>xPOCccZYzxkg*|C33I-jcj^ ww!XBo3g{&%?To}qmRM8owo)61KS`F(1YbP6+gn-rI=uSA;FZhq+&Po{0Tszp00000 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Headers/cdesc-Headers.ri b/.gems/doc/http-0.6.2/ri/HTTP/Headers/cdesc-Headers.ri new file mode 100644 index 0000000000000000000000000000000000000000..1ab4cc14286185e4be4f910bca053a46175fa49f GIT binary patch literal 749 zcmZ{i(Qnf*5XSR>oV49qU}7MFP-J)=&9g0`R9UB5qTMvQCqG1v>n>)A9Xam0KOZ|y zB?j!}Bwuph-Tl6M72Top+e^(6T4__WDyvxA(lZ$mc(M>|BTNerm|qe2cClXHAaqP( z;Buqu;+NnSV6fKc<3VT1%)_oh$cgT1p=^XkX~T?dX{d1+;fMxkm~Ley2>ejVVp>|; zOv^*BZ>I2KC`olKZSJ#D-M9JH=sLHos6?)}IoHZM`S3ysbZKhrIqBYx>z_w7gydO z3q2n^NXKrAbex9#U;7dYsPk_!SIz+Ap>+oJ@cY`A;nR?Y1P-~s1Ybxa8lq9ND=Nty zw-AjRqph=DY`W)3W8@>V!aoQ+l^smp_4K9q)PKO^E>2wRhI{R{*)y|wVY>8-_ou%o p=Z_Un7NMW6snm)_GB}bBdOt(Q;thcVkJB5*-~V~lOTF1u;y0Rp)(8Lq literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/MimeType/%5b%5d-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/MimeType/%5b%5d-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..84f09e160aee363fd9c73d264c1f556f2996c26f GIT binary patch literal 446 zcmZXQO>4q17{@(~>L$AtWG{!%UED=`j+gF5SzsL^-6=>&+tdcrJS9mHzx`6(24mOc z|MvVYMxQv`yh4HTlRl=x)lkw<4oNhm+W-g46^SNqS+>SFm5s=bt-#p-EP_>r$8DD@ zSpdE}C#2l$yB1>~*EK@B5gsQkH_p-#;QPOtH8*@`cv}aHOB#@9wh^u~+9F=^)(L~S zwNOazM2Qa4)hH$D5;@=RyR(0B&x-5)yVPO;i>p3zM53F%oHvL*IAC^rGNay2qG@8d zv;xtkF<`bxR!GBdbp@R+zm;KPPQws=QGQZ?d4{i&N-9C3TP5>(?OZ!=JRH`qo02GFYyC>yZdcwfNSGgsV}wcdvT)TJegiJ(t30Z*m9L8XIJa>EkL1K zT>rNSa7c4T*~v}y2W!tbTN^liMJ%Ly+F1aC-?iBJ7$%vO&i8^D9>qK+4`=UdZ>5uu zPTDOC={!0AC3~D>SDOYG4F)$a@?tsn#9=P?3~4HivyIZ2Cy7?oV(YzKv_!QGb&Gx7 zPgezkkY=V;zTBd0RQK4I8)w?m%SvNuHf3!(Pi*_LLT#Q?K2G^06(f2~&{}5q)T7ax zZV>w_WW>kWF_nF0yof}UC*wM7IzWh6L@=?tN~@ZNL@=|?cv>blLpZfg{goa=kS9l~ z>%Hu1Jhbv@NbsY<&d3fdzpjjXmaYk+KH!=C5bWV_r^_Jtp9i?7p~`e3R-<%(Ardyo YXW4O{oV@=6guAN0zx_RhX?7Z40CJ$O%K!iX literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/cdesc-JSON.ri b/.gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/cdesc-JSON.ri new file mode 100644 index 0000000000000000000000000000000000000000..7c86a2b633cc4855c3c060b45fff8422037406b8 GIT binary patch literal 564 zcmah{&r8EF6z)OVx^4p*DB{4;gW$#X{CcVA#0s6mb*CIk+Gbm{Z9GrOBzNZ$=d2)JL3EnLQ9PYUrD%eGrY6t}SF|LNds))V+epd1N(oPOpZD6Z`bK0* zT>^f{Dk{?r!3C|?O}Y}SN+r%plCo8rvsx;tO`4ICefUAo4;&vE-La4rxxHMQrJ0b8 zEO2<6l{8nl1w$^FB)KF-SN6G}?^qIDMDBprjl^|M_E&>G>Ij|fR@%9L#cLvGYliL* zuaFfCG=DHu(Lm;M@BN+L<5L1GlpxA#WK+Z6xo+&XGQ*R|9UZ=;rp?cOe~y?HZArcX D+k~gH literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/decode-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/decode-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..62424b4e0fc8221308c0bd43cee7d1cc5e49fe06 GIT binary patch literal 303 zcmY+9y-&k15Jwr1X&VU%sbT?%DlD*&%$FsI5;aIE6@)2+2^7pt<|02ES-a%Tj<+vofG{)8kX z%OEgAtt3adInEW#{tO0S+#a;({RD#4Fza1K5N`i78)n(oGSiV{T9G`wS{~ePvA2+f zlrT$MsYD*$DOpFI_a@R~3iV@4^zE>Jvh{(BQ`FMaPOwJyTSr@qntE0%L9wMAdq1W) nS__50aU54?c{qD;-ahWH)64PG>B*V#>to~^t!C;)G3VkxxZGbq literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/encode-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/MimeType/JSON/encode-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..879a4e6c5db40b569eb7e4ce90abd7e874644031 GIT binary patch literal 313 zcmY+9J5R$f6h;}4=|f_wSc*gx7FbB;ns9H()yb0gak>c7W*EbQlg z=iJN5H!MD1kpn#U`$D)5n`$Ai@^CJCj*TEdR#_efZ)LdwD5MtUeh>ifUmxrHGm?-j zgZVJlN^*qdX|7=AXB+_h_NYbgCNNJ2W}K}E!tH-%!wlORHgqJJRwNIXtE1ZnSnmXP zfy3b7BMB*CmbOxfJiJq~jymUtNc$-2d{wlw*gu*2$i*pY>1ZcdBm1qTtwBv4tCgVG tQjWdzQI^(1;cpzr)kPl89=z}IaGhTJpQmSM#&1r!Yc!gv7safN{{Y#VV&eb+ literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/MimeType/cdesc-MimeType.ri b/.gems/doc/http-0.6.2/ri/HTTP/MimeType/cdesc-MimeType.ri new file mode 100644 index 0000000000000000000000000000000000000000..78e27ac1f8dec988fee351ce6fad66994f539ff6 GIT binary patch literal 660 zcmZ`%QES^U5YEG})uauD&<(ahgP^ZXo=-1^uBCqPD69JmJb#aNG`8(I=e2*8-S-* zmRv0jeELT(g!{3z03p}5L+uGnGAo?#IWa6HjPS(3=jX9E!ilvLc9TRnr)Nc8T+V%{ zI7i)>78fnXV=h`@J-R+&NeSa@B^BoMqmuPvnA za;B@is1;UbRW(NYps=rMROZ)mCvU{YIi)XiE_TItx!L3y;q(>4_ulAzG#f7ihmVGp z@-(O8Mu~ptg%h5_#BOUP8-5V6l;4LAg4u6(7sIA{n3nv5F*>91?Zn|)_Q9rVr+5#| z_K=bymL51Twa$2KJhnky3WwIopTc9jgz-z=d!d_HqKrz}VFcLGuusE2;>q3P{4b)Z jzdgWh$R~~FM2`M*YVd$$$Js178^UEa_Ee4E~8c(4tn{?AG-RxU-H%k5M-L!~^ z*T>9n-ppSA9Y*s1>8n8XID% ydy8O2N|e@hHl$zzKf^H0dr2_7=>WH#JwA4e9{z0UF4OXKH_7XE_7s<`VBt5+jfJ=X literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/MimeType/register_adapter-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/MimeType/register_adapter-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..0bf6b94126f7a5daea9f9f985b852ead6caad385 GIT binary patch literal 849 zcmah{L2uJA7~KJ7-AXw?5e$&{lnS~@)ta-rLyA}-h@c4tE>RUZ$(P2PV@I~j=)cEl zQpDN=xkUNim-p=V-lN_RGW`BgW`xYeCPY)pJRY*+z%i-HC0B(eM#Ot+_|BO zt`x0HXLb@hR&uVj%osHYVGv$}vAS^2ObNTA&7A0f4_G!b{5xp@P%W!`^*A^4kwd@{DoJB}-M9dF2YkF>j;Wbe8e=C@Nv3QAH$zR0Ez>68lU2+!HFRRAF1+4m>P7z9 zU}*zUR2E=tURg8-gW@Q@N7i}pdS3F6=2lQOedLO*L2qkGwG*;WDz%tjguDOjy)u(g z%jL#G`Fb_#)oN1Ip<26;?f_KxtpwG%M7W+#&P(ui=uAp#gQb2W@(=6KRHC$Pft16! zc~pZV|8!+Flf&Pv3qUJ0%vMIB^d0zUIG5N8$6T<;KN39a7S`&nbhVKBPp(WhhXf%= zZb`xDh^t9S#s(y@G!u-#nB<_WtD__t6YvoPLAn7(q#JhLstDe?%e>f}UoRbMv4>5OdMXljTe^ z|HbMPvX5u%0Cx6wuV}zyo9ShpFWavKl9#H^uV0(y9pKH8MjJM9e@vAIe>^wqq4Muv~;J@aUw1QC9ng=$JQ)!J`vdx0OF#es literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/OpenSSL/SSL/cdesc-SSL.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/OpenSSL/SSL/cdesc-SSL.ri new file mode 100644 index 0000000000000000000000000000000000000000..7750077c95b720c3f4b69aec8ee6b8644d902fa4 GIT binary patch literal 389 zcmZutJx>EM47~x}g?_LwfYb%u51^Tyr4mqa5(PxtDZ?q3rZgfKM@bI&`6NZ%Dod8F zXFvPB3$lfqk4KaMujqSWR=69C;@6rqHCeA;N+_R}O?~&g*}Mb1xv0^GTqv7RfIPy= zB}JJ1)2xL58XQ349C~FVf$_o#9|JF7wAgE-D9{D=I<^NTcG`Z1cJHxoqv(ukao8C{%8fjtMwh%E8F&3vKxh~vRFH5Hk%g&=xJG%)93B>4Pfn}vL+0}iKS>s zEKE--EABsg2aqKDPMU~eJa^p3z%m%k_ex6wWNteZ>x1O2G9RJdd)w8KH(J(qUkhtu zIt+Cqwf!b6J66u}svHT;LqHU58D=?*UEgRW5}(7B^EOHmWqX8$^XiL7Ie@C1C=((# zLY`0QcpzwT?32_phIVHQi{XKv2(U?d$tuGtBbMfvVwTZMLPvz5s=U{#nH^$uGkZ$p W!8e0`RbKxKD(#ly_HV|E!No8A;&BE5 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/argument_error%21-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/argument_error%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..aed73ad1cd5a628a818255de3f9367520a2f094b GIT binary patch literal 265 zcmZ9`F;BxV5QgCn$W*jqiVzYLW+@Bxd|iTohztc(g(-vOq)uXC`>eAI;@^`JCf3vG z{hpKgJ7l{@Yys~5_g1F?_jP7YOP(p}4^I0eH4)M^1NKyuoIh998^CKw27SEw|FmI6 z0n0$>^;=wwoj)e<||qE90-%0^rK5<=9olAo`fj#2gc_E^XlqkH)$9uGx(F|l5d LoU#vA#VCFN#DP}M literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/body-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/body-i.ri new file mode 100644 index 0000000..acc0ac4 --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/body-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" body:ETI"HTTP::Options#body;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I")Explicit request body of the request;T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/cdesc-Options.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/cdesc-Options.ri new file mode 100644 index 0000000000000000000000000000000000000000..12f206028570e0d83dce16132b2079bd3facf736 GIT binary patch literal 961 zcmaizO>dkq5QaHaz`}0SB>hy?L-_#>XZwPbGzy0_Rk~3RR%ID5ixYz_+ccYhUmJEw zBQ5IDwO;=KU~h!J zwZ%8ZJuQt7{j~s}M$R=+54{AyLi?6>CIoRNi831b0tO)rkq4rzW}N292hNJK#u#}f z##~=j;b0)mM9U0rD5+St(YRKk#fB7|Vo~E#bjFf3E+`j|DO{v5O3?|5^5kPhYtnOr zwJ0B`!KLfRA@d}-{WY*-*%zFZ)-spgfj&AN)_ME~gDq*YN^_|fPrt%zzEzB-8@^4ADL+eZI0U+9O2TX zgsZW{H$-g)^<%1(P+xYz9`f(@cXIATyfpy)wAI@?Lm~6h{e|o#?Po_;TJG>1pnU)D KrCy7w=kzav=K_lW literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/default_socket_class-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/default_socket_class-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..98555c8435430b8466acf547ab8cfdff9b7d5952 GIT binary patch literal 264 zcmZvXJ!``-6h$)>)ii~c4xu5NrcR0Hm&GM*h=zU;6gp%Ok|H-EvY(Ki>EDl2PlfK6 zbI!dgc5t_SK@0Fql=k<&5PW)YweA9`jP~S6*`RY~z+R=`Pa7#e0X`ymY%{>W(cV32yA?^L;}Qvw>+%n^G6_;Bn$?Fu|V$YlxILYS4 z{le-7yU1oA>@N17WZHtAVe3*b*cy*Lk3=#qB>bv%bEf3wpXd>?@>f&HE0)ftho6J> EH?pHz%>V!Z literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/dup-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/dup-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a4bc89bf5e6e2717bdd4a039cd85e646dc8a4632 GIT binary patch literal 245 zcmXZWF;BxV5QgCnD2*D%szPEj3oJDAbqOks@K8V~oibQ<;t;Ej&$2H<{Cg6G?W9ll z=)FlVu>E?)2H?g0o;CH@)?2gYENw@hKyoTM+r3rQC%}g%gDyVI!yze4$o#0RX%Oxg z;Vi>-^Z*k#4%$%)S>a`%Sg&AHbjE7V?yOP!p2+WU;huwL&C{OMH56e|*7OLs zvvQE}YYG6FoSgQwf}#pCQtB44t_EXu)~r#xktpnN1|Oqhd)5N4&>0e=mS^KHNemI4 zAgQbtIEWrSWibh*Eq-&(yG2uO?vX|vAO8NUBByTtBlDr|ujiATk~@9OAbaMFT)lAq4)EraK^FnWvdwlJ3g0VhYJ{7K z*vs(Udw{{~JMB^qMd@Wov6{ho*%+%Cxwb}a+LZhTCvP3ppmCrjb|#5d%Y$)WQ8WQN zk)*O(U?XaDX%M4O+TxK?TFn?)+@6fp{p$DcZe+@0$H>KLb-b)Er?*!OowScu#z_AG DFq=-o literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/params-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/params-i.ri new file mode 100644 index 0000000..22211be --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/params-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" params:ETI"HTTP::Options#params;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"*Query string params to add to the url;T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/proxy-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/proxy-i.ri new file mode 100644 index 0000000..533e8ee --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/proxy-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +proxy:ETI"HTTP::Options#proxy;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I" HTTP proxy to route request;T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/response-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/response-i.ri new file mode 100644 index 0000000..93ef028 --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/response-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" response:ETI"HTTP::Options#response;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"=How to format the response [:object, :body, :parse_body];T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/socket_class-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/socket_class-i.ri new file mode 100644 index 0000000..503db19 --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/socket_class-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"socket_class:ETI"HTTP::Options#socket_class;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Socket classes;T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/ssl_context-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/ssl_context-i.ri new file mode 100644 index 0000000..78914a9 --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/ssl_context-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"ssl_context:ETI"HTTP::Options#ssl_context;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"SSL context;T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/ssl_socket_class-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/ssl_socket_class-i.ri new file mode 100644 index 0000000..2f7c97e --- /dev/null +++ b/.gems/doc/http-0.6.2/ri/HTTP/Options/ssl_socket_class-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"ssl_socket_class:ETI"#HTTP::Options#ssl_socket_class;FI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Socket classes;T: +@fileI"lib/http/options.rb;T:0@omit_headings_from_table_of_contents_below0F@I"HTTP::Options;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/to_hash-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/to_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..685c2b323b6636de858493c0e73fa23d05c9cea4 GIT binary patch literal 241 zcmXxeF;BxV5QgCn$gN1n3L)6S0!!=px}>6w$WTBioibQ<>R_vm&$2H<{Ck1|>wUUM z@73Z2tB*al06YJE)MW77tn9qXmxRK|WEikRS><;xb^Q+T7RaJc5C7wql_g|hP|mgp z_mgy#@iGK}ksW&NX#rUgWTe#0;JWCn(^Y=!tlAi&u)&F3N5!_R23}xqNf<59)_*3^ zMeGGh<+Q*~wCHIRlTg~>7w5d0Rr&n!>G!qB#?Iwm;dm(9o2lm&V=vvalPU2Z=)p|~ literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Options/with_headers-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Options/with_headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..53ad8a2ad2e74ed5ccb49730b2da87657c2f67de GIT binary patch literal 258 zcmY+;!Arw16vy!$MjUns!VtlOP%rM{a(=s1)M5|QA>FBmkaX!9O!GqW%J9Fpv%7eG zJiforbhd-V*DKZl&+ccVsl|P@Fc(F7eKgdHR?EE(kpX+li}e1zEVlrko(#J9@b6>I z@*EQ1D{E?myRo^E;k)+$!$99@M>9w=F9XGD0+(51tS-`9Yt*VG@+%y>PeHLYD}iU& z8Tum_cZi}1*a?!#YJrWY(a}(hLTQUf&UrN{(yPZaczG&h$zYzJwZkE=Z${P!hECcS HD`VupAP-a) literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Redirector/EndlessRedirectError/cdesc-EndlessRedirectError.ri b/.gems/doc/http-0.6.2/ri/HTTP/Redirector/EndlessRedirectError/cdesc-EndlessRedirectError.ri new file mode 100644 index 0000000000000000000000000000000000000000..9de5a6fdfeab690b1fd19003c7bfd971d35fd4da GIT binary patch literal 568 zcmZuvJ!``-5Y13zlP@Txg^~`&YfIz#JT%ZI)I&l@lgWdT9XSzIbVj=L7@f_$#!lxOMETymkZ8-%cDutg?Zvu0=k_|RUfz*Tn*MT_RH&BQbi`f#| zqf#o7gaak>;g+ZxHiKv$O@81+Biu>Kwt}ynvdv0^yNr0QM22NnpeASDX1Q=jM{zrf zJ5ky?EHCwvuwB%F*Gj3MdeEu%xsrv$J?K{k$>lEAhqhZ8`N2ulO%nE`w#0QIn$fsh w199(A`>wW9wrawBu5Ek~z?;*Ps8e6IqEn2mlPNa3Ov3BGPvzt%#rY5U0dgahFQV$6sO(qXUc9dAu_KB0yr2oFM6Az_D zaMJOf?w;Q1%H6=->J>A91yae2X~DIQZ=@Uf4{O9ZufA7eD@kNV&xnv1u-RMWKfSNl zOMn(b0{EXEGRwYi*;-+x#kr705JuLdXdK1OT=$K*XxS?xzc>K*> za^id9DrYqu`7aAJawmoMOwNsW6dnnl4dq-5~4*ai>{M z>_mPyt8J|-#cu3CPaV=iW)^o~s0fX9S8SWKuSkAzBkCmb2eQ(JSD9$9hW#1{2TdH> u*ooPuHE~+YI2nKsTTfyYyRs8p?CV@avB`Dh-?rm857rLV&LaE!4}Jh_U#Kbo literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Redirector/cdesc-Redirector.ri b/.gems/doc/http-0.6.2/ri/HTTP/Redirector/cdesc-Redirector.ri new file mode 100644 index 0000000000000000000000000000000000000000..7af917e125c6c46075f1a0b2c7c52f763a083bbb GIT binary patch literal 598 zcmZXSJx{|h5QZ}#Cv71eDqw&iio{AYpO;8&5gzzZDU*lDaa>|ZKOeiah>yk6 z`Ofd%^PZ2QXElPrYU3lDS`R>~IfTSmKX8;$6r})GtaJ)Om?%dh6Uz@YbiVq9$q#p&n8~>P#MtY%8&-t*1(I(w|@1Nrq60 z;EBiGJDu)bc^iDUeuV<#4^R!Q=QY(jz2#mUOgBQeQi3w9TryKZ`KA;ogwfj~4xZnW zWQFmXeYZ>-jQ=4MWV!bj+@p#G08fukFRA)!CC1iA+c04~Jd7k&MyCjf>k-f1`0s5Rze-I{k4|Hx33x7h$KA zdZ~+tvdwE=Slq=Eslc$p=GnI+sra56)-`c3=0Y1P3U(ePqYfbBzD{g)QnWcoHt%fw g*xWy@9tV+n+zC%%IVV#nx{iaJi|noTqWHV;U!lLB^#A|> literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/UnsupportedSchemeError/cdesc-UnsupportedSchemeError.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/UnsupportedSchemeError/cdesc-UnsupportedSchemeError.ri new file mode 100644 index 0000000000000000000000000000000000000000..f5115bbc0cdeff8ecc5c662abbc3af5ea39ed676 GIT binary patch literal 526 zcmZ`$&ufD)81*os^cQS{ZO|RW;|{CmcoDjmdDtkeo;*m@Si>}5mc({{{-SLUWsJZV zKHkgwUfy@(B=}+b1_j2SAY0Nb8=_Qt&z#7cCtP(xfYh|y6*XZCRvi!N_iVQ?GIgal0s6YJ1Ugk%SzY2QTNlyRjAFX-iIFzJC{I@Fn|R*I5K la?9SvkBNV0^ce8eVU~Z+%sQJw;cevIU9G@quZzEX{{_VDq1^xg literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/add_body_type_headers-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/add_body_type_headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..de94afa47e8a72f3789eb5fd945d812024fa4cdd GIT binary patch literal 411 zcmZutJx{|h6l6edO9z&U0g$l50t?Ojx}*XkG89!+5JLvbNu0*26NhJqDE}Te=>QVr zJ>9+gIG=vNV)vpmfOXw(ge`TREaW8eu6drbROdajeIr;YcrMToAg^KM`EPN&1=xwN zRu~KLiP8$Z|6j5qVF>f4O_j_v+>CA;j)%4ZaMo=lYCDB_&~UUSAsTM~a<&}#9(hxe z)huz*;&q-IYD+;+si@VzAmxa>r-jDhxR>9erZ`5W$40ahjw5KN@gVCxB`Xp~-mH_> zIgl7Gft%hK9rc~URCq308(1J4h1CG9Ycdt+FEx?+~6N-$lpOxM;GGb|NK kcfRi@XOTB~csxpjOE=R@@l>2NPU~SpWb4 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/add_headers-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/add_headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..dad6f1d47d7d014a54b5f59d251f96a18dd5e1f0 GIT binary patch literal 358 zcmY*V!AiqG6!ak5YCt>`FA9bTq8F3%3rLDKm_wzMh=&}OO?J~PZnE+1hSI+`O(N*= z4Kwp*=5+o6i|wl}0G7>REo`NEwve;LyJVcxN-!?a5Fo2K@$TQ!bOW#z-<>cP;1i`4 zc=wkWk~jvZ?Q$gx4cDXdn&DU10`zaXS~PYJPSi5ACL)-WBc5O=0fRx5Cqvt;>{i&kJ9L(U&a}y=_m literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/cdesc-Writer.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/cdesc-Writer.ri new file mode 100644 index 0000000000000000000000000000000000000000..76637f1ec23a90e7d4447e2abbe4be4cd60ebda7 GIT binary patch literal 952 zcmah|L2uJA7|j8>X|r{}#55HoLT(_SIop>&yNO7HRb303e6XCvUA?7ou$`9ud+a1t zDI4M#Kl^>}z3=6TJBKIJu}C5OCgh6dqns**kGUHM-Vez&lK_IV^EeoMnaw5;PT9|j zDGgx@B49A@GPz}`1_;aqeA&=_rSh&SAvE08iWS<0UQ|-46$S!zT;yU0_M!#PSsc91 zc`{sTT@GbKKit%#Kgz^%!Y~pmuE~BjC!g8?*Q8z@r z5IeXthsTYUktmd=g~mtRiG%KFdU0-ejd1@_QxI-%gkh@{2>5E>*Mv%XBWbw=#tMjo zxAu+Cm9Lk~uL{0qQqjB~;Abr7#(>GvxIx{hZv;mDsFOa7KAa=3k@@2Lr;B(@K3|Tn z$?SS^cGXCJ{}0KJ-Tp&9I%svio86a8`D>c<%-6zCj9SGqpDI5Q*}bnsB~$j7&}dKx ziaT-8OKn3ej$Pb=URfnMPcg8VTd<8q{<~50uwP1{O=(zWR|OAB$=6gf`w<6+yk1zN z!_Gm6*t5WZW*MO+TfvKm$0v#v8EGq5v+jsa_ppX> zhk8m&MpxSd)VH$HQIo=Hovrb*6Z)pT>0mJ5{vf85n*B0=(v?Ypivqjc+1AZzOAMlZ M96aCKc+E8U4QzE6B>(^b literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/join_headers-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/join_headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a1f5362e493df67a8c3f22c1e99c6334a8024852 GIT binary patch literal 406 zcmY+AF;BxV5JnkLTF8KqDi)Bi!T>BZ^K}UVA_6L^sv?FAk>g$(gA)h)qN@KMCn-b6 zli!`+_Z^QvVX}PI0^qUU&5=sIPA77d1n1vc)>(;sjmCQ5y~Igy`?^{!0G9aMq9uSY zBMHsT0Xg&H82qNql@uB-hud>*e%c1WebiQ1(-{1y;f8GLX}CIM7ToZS;Z5nyPEsfG z{^mq1qY~NPhS>&%EF`X(tosKu7`c%&<4kB{P>|ZOLYs;cIntYXt0cHCi5m8g5BHcQ zBkN5Ez-d%Sg^p7)pLXnY&rY{})(4aKTo~y}QeTf-wOL_wl@ZSsX1d6PuF0jeS&m9? i!!S&bl3;Xq->pVxu1J4q&dss77~+3)rs_#?Yr{XAGlu2> literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/new-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..29002aa7edb114cee9770e08e24b4f5a768a6f56 GIT binary patch literal 282 zcmX}nF;9d*5Cz~X3=(NCHWpr}yyPO(V}nsIQk=P5)>u$%c43gsEe!4sA@}bEN$jS0 z^X0v(@DtXjS1JLXyUPK&p{iJ$>pTuS90Lg6L>}M23vmQE;m?4c0lu7JbO3YWDcB2$ z`axS$65K7+LAmqL15EDFV#gswS+5-XVg)x@Z7fcxH9BdS`@}77GXAlTPEV+SG^5tA zY*1CE`}VSS)Jj&`qNG}u)bRv+snODyrfIRtkF&9zjsT~419&4H zkZ%4f>{(GjGEU0q#=%u29VC5BBfyNE2DD)XNj^#nzFxp(-f4qndTq4I`VhwKPa!-1 zQg)=+o>jneH|Xf4?YkEpxj_V}3<}qY#@R4G_Cld?XU=)ODAVQb-A^@7<_Sr3o^#P` OqScF|L7E36z31Po_FP>6 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/stream-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/Writer/stream-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..21d187e05af52ea960b1b1c991e5f5636195678d GIT binary patch literal 321 zcmY+9K~IA~5QROMZI#4R<3$sZUi2cIhYLm}}nBSWFqmFA7i=8HM(Z% zbeUY~S}G67A`~fHMwQZ-cz0SAe$CwZC(=KTa!;lhxgerOabBa`sdjJk%21QDEHvg+ tkerm5CyS;SWdp;aRYxirnhX|j0BfW72Jym>9lcYrec63pmeOrLl-_w310jWD_@g zlH;Fd<0RX%64K1{ig<^jQNx$#tus9*AvJQ-^4bg(ianR8%`r{WYEi_?`-fjNi^7L! U9vyOCU(T!EjO&Gd(!%@n1h|o0SO5S3 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/__method__-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/__method__-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0a91833eb57845249ab5f85d7245d17658767507 GIT binary patch literal 388 zcmY+Ay-&k15XBi#C={tng%BT-6_&z~nhm*25fG69sH!k!u$=VL7;Im#oudBtm=*~b z@7~kz-n-r2D;v)5v107jte?O)xG08lFN+79>&?h{#G;2hi_ahPe8$)uK00vz;*UOw z(vs`i!~{MSkSnF1(AmM#sUy64O+4S>m(XSMl`ue=p_j|G(e(B6tbUa@%C#X zqw9nQ&$q@7rnOX%#m7pPOqphR7FhHWGZI@pxmvcDdk-pFBSRWaiqLK+8v2vs7@Fu{FzK+IHI665(@D zewDv;EkI9pwP`4VY0@fBp%}qSQdwsN|8Q2X&P46X5A2uM4=hfwwj|F+9c^<8vhr9< oQra1bl`OHLUJOzjhyQV!%mkl5?e$1nz7HdN^tE!|PK6NP0deR_S^xk5 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Request/cdesc-Request.ri b/.gems/doc/http-0.6.2/ri/HTTP/Request/cdesc-Request.ri new file mode 100644 index 0000000000000000000000000000000000000000..fd74ecd76e5cc11a738d6b11bc080760d1824294 GIT binary patch literal 1233 zcmaJ>O>dh(5cQz~Y#du{+O$=w7NJT#C3bqqVfRAhI5h_+mW@w)K!DfrwwR^6OFsU6 zXThW-O?p8v!@l=s=FPscmgr!9&J%<#x!6YOD2=2f`^@s)?wtNEs8j|r#uvW(W)cK5 zgz6wRAZB01KWU;2Yy=z~Ryfm0{3>#U0JPZBOj*eG@<=F2OpZ+pTcm|L-kPPo z9&D7#2cqIS7O@6HLyvEn3O6)bvFuugYr(gnisF=pd>tk{Q-CbPn5O)8Si|DB?|ylT zIJgx|QLzKYogr=y;Yn=L@!fXJSNEFGca3>TZ0ALsvIJ^-Nt-^`$pybF4|?ygec>JG zpe>UP-O?u9L(VD$dp6O&p;gJXf`=nr$VkRBeXM3_FVTM0p5LVMXH>oq~hr88rtsY zsZinEL}^i0i`!lgTI%&YGx^s{!zJ!kD!bEhFu6KkR1y!LNNgk<`taUP$m#rIQljA5zb8e5>1@bJ!e*uN_(B`u%^j#2~P?JDy27B#F?J z-LcX{f7hfM*8wq!30_Y0%IhMCMNDjy7BNu|46b0a>8kwf=7QZsis}#F-D9Qql5+UF zLnTx{47XHm_$mxF9;^lYZC4=(=shuUPlMn-JX^$A*0%=uSx*$91+aqaiN#vAOIy2@ XHNj!8VQFzqsz~V{B5O@ixO-!@mh(CZvQ;595$SU mG>T)zOKhnZJ(tShf0QQEEc|-=>yfma44bGc=w|JenUft&L8~v zCeaz@`8$>XJ0gF1wvphoyYazd%YYpU!I#IPI05A5)|)`9zqnDC8_IDN`PNn_NowCR%6?c*=03X{MM zH^1cE!^uswfrr(rVgMgXmsCzAHHO@aD2sRim>jIFCoMBCx zPbM$8R6hysB)FT9pj{yev$(^29$tw=B!q6=6jCt9Lm1RrS zWh|{2zdXe~4{*P&16KorHkXX1-o~#5_;h+gRU{HYa!w~Wn?mU@i*J3(PIAsh|37V^ HwvFU}nG}et literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Body/cdesc-Body.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Body/cdesc-Body.ri new file mode 100644 index 0000000000000000000000000000000000000000..68cadd28e9348c19834e64c5707de94cd709e78d GIT binary patch literal 661 zcmah{J#X7E5cLpHik(jcC=j$L1kFLL`M9V}VpK!hAay1V!bzfIwiGFlblm*=9_4rl zilX2kQ19-&d+&IVKEk_)TiXJBv#v*dqtSbDq0%Zp{A{}y2JCK8<(FTU%X@$a=?81P z1Q;>S2%3Fwe#$m5&XyM5@3_9A`?VPWh4NMsWrEExwkh)z2ZCw2Qd(B| zN3ELqI)q`qCz?m1YuAirMQM8#>b1m1)mmtR)`55 zCMc)VJ3}U2tR6$y8JzHGc}{iz(-w(Hs(jkU++({)MFO*7(`eNaKVhkn+lZ8xgq#e{ z28vsDB%i?1;M6k)8820Stc(w6+HsCZ#E*9LhZ0-Ll`SGim7h_pUEGI4z5mOPBL_d( zyE>CStC+4DP9*%IgD|!^1R9~-aezK-TwXj{s0d6 B!R-J5 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Body/each-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Body/each-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..243a862d797dfacf55983dd108442e4c0cc07e75 GIT binary patch literal 334 zcmY+AO-sW-5QaU-wzc4?cu{1D7X`67%JdSyf;m)5siz#mZZc^WH<_?IRr>GUv|c<8 zyz{&tr{hnUtzW4GcET9#Ko>zIHu8;O<)Ncns5|SB`xy2(JEXR?4ZZQ+*>AlU!ucW5(zdqoi+i zk{gsdnB7ZdE&Z5oD-BB~sZnAV;7)0aVj(tgmej^#2y2a=H_ZLq{pFnxga@Y&vN)mE zaM7Tu0?ik-qqg9IQczu#)Nu&x3yr}pj^q3!i$=G1!)tOLrkD)X!iBe7m?`p&k-KP$v&UlI2=N))kUW$iJ^lx*iS> z?=t^^&FK>*z?;49RUEKuH+t2SxmA}8vM<_{Pv4Xt0ZuA7v_S#9V|N9Z53kvdLg6N1 zv_yEkNqg?klLJWXG%6c&C~C)j4DAB$>s}j`Oru3L#ONyj&sHL-FJ2^*0;zG-kqwG> z+WrRCdmLHh!YGD4lW1dd0~5;Ng%Hv%nsWUtjZW)!2I^whly`IIoG2e|VF&ahHy?(F GK>h%a`A`c0 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Body/readpartial-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Body/readpartial-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..71d9f23b1831caaa9f8c3cdf39d319974afe270a GIT binary patch literal 400 zcmZ9I%}c{T5XC)6Y^|V&;zf}qB7Pt?=jkO{4dzfOC7yB!v&lAD-0p_miIV@`4fUWN z2j0B*dvAaA4%79sDFGgJzZBG%Dxb=OG(52as}?OuQ~?ApNg7_gX4wj0EnI7~697-9 z>Mwum=0TFcr0uwprGc}Z@e=Jv*8=#IZYwm6U=k0;E)NWx|JAI}Vr{W)g84Z26pOW| zU|q||FeP+N4dXotch7i7%nItPW~h5sAt9p%>Dn>;M5&M~!Gd{^rC}I5A=nOnp`=In z2c5xTypc+z;f0cX))2Kb`_pp9eaQ#Q2P=qTvz1gd9!l!k6&q`|1r1S!*%YPGAvx5QgCl!3p&mvJ^sbmv*T&UotqfHT94Zf;)K-k}cOFvQ9{6O8f#kievfW2rp8+l^IJ7|loP`g{KgPj6DN9J* zB#mwn?q}#E{B?2wQJqF*X$@)Ngs0Ff;I8PkQC0R}w9E%0m-~MGF literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/add-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/add-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3cbb28d33feb7d5f84882a07fa568d7345c5543b GIT binary patch literal 279 zcmXZXF;BxV5Cz~4C^hw3u`qzb0t@kc?hph-WGJetFlDfu*dZ29F0vgV{ymP;`QCkc z?}~iE{``h5z{~h|)S*XJ@6EPMiBu|q}2yHZE#e&z`vy7QpNK!E0xbivmf*yWwEx=in_X|g_qDRUP$i;>7ayC$j?up9>y zM6abXezaFI4sY|3E|iEhVOF9DJxU@sAP~& Z%PpsI5?v=O_1l}Z^e4JO+E**RXa8A>Rbv1E literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/cdesc-Parser.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/cdesc-Parser.ri new file mode 100644 index 0000000000000000000000000000000000000000..4177349fe56fdf8ead78e62bf4d56fcf908b5296 GIT binary patch literal 708 zcmaiy-)q}25XbW{WY11QM_?5CGW-WDewGR|bSv{ix00n#dN8tmX|&psk>qy$?|Zj7 zOG^jCV9@vOKKJuYe8b;wKHG-#Z`SpyyXchna;4)kORtsl;239LF3arf>vnt1`3C%8 zjR(#rt6*qMzt=yZ2~4o9*XWALKf0QrJTGjoL$wFhYIEzWowI!vRNX;kcU5Cezzn{sp|cOUc$zL(HjnvB3XKvYW$YT+q6H1sfxdiNo@WWtpvB-W(-sUSI1I DPtMBi literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/chunk-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/chunk-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..df76fb83602d9696809459482fb7669b01ea85e0 GIT binary patch literal 253 zcmXZWF;BxV5QgCn$gP^SVqt->z(PD1Ts7TfaH8dZ%c`6~R&Ri0${DJZsQ9q^ha zlf;PfY}{8AL!e0{sVoW_geI4=9ECzl-<f5be*ZIYutqvphj||vrRp+;FO>+P^VsK;w0vx0d=x_de zJ62VYxmg+A5nL_Uz4TwR14tk9gf?yp47^5rviC&~if-=g!c|so^8L-!?&hOru<^XWS;K&99I7lDR-~QKj ztg0Y$lQOy^xSpYV>AxlikRGNHZCpWCI_YC*7jRkj+F+gE7_EvSMpyVhc#$fJz4eOi zSOdJIQAcrp()Kfm-qR?eR0ak0q9Ypr-a{ literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/headers-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/headers-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b8127559be8b4b2b4f0a14814138d249ca98f8c3 GIT binary patch literal 262 zcmZvWu};G<6aX2J712sCv2>~2on(Gpg4#xS098?#I#_mip%zY__3Vh>$57bVPj`1+ zyuxj}ryk%jB|hD`LdoSB%^PwQAP$|9o2RZj0<;(dO%VZ(h9mOkkJ^exNzsa}=wK0M z>s?QSCRKTJRhEqIU!A(6lk4mn+v*kIZQ1Wl0%t$Ugu>Fx%HH|Lm x@1C39qaK(>os9LUY0y1QDVw9V=;^a+>ZOva|Ch6^>F+ORFT|tqJ8xpFz5pzKRfYfn literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/http_version-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/http_version-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e5f7cf173d34929fc59efe0bc73addd47e3ef09d GIT binary patch literal 267 zcmY+8F;BxV6ofk8{qZ41~gC@&>y;OC+du^H{zzKsR8xY_qeL#Qr zuexVd1(}vHE3bN8kA49u<>$2Ad>-^SeRa{Vo|2rsBCGj7; zVtdvAFKN_K3@Fdqegx5b8by@KprBrKWMd)+q0rDb=e%9i`EqxEnU-0y&t}_{t8P1M Ny^$ZKc``Bt{tLh}SAzfm literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/new-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..177c2e7043163f311940a376a7721c1c78cf2d0c GIT binary patch literal 250 zcmXZWJx{|h6ougqD2>Qkv9O>_un^CeC8!^2hN7x+rwo>z-Vh7N*RmZ|{CgaQ{hUYd zLw<$LWk(&rr~N%)9O%|=^tvf?i}wt&J#WgFBj;y;3kF9vAi!DrfF59;d}Id>g`1So z9l`TrouvPn96*An5pB$&sGamNv@3Y5du=eOMyqOw(N+E*uF@pA?_MR91FLD&Q4A<= z+I|Podm2TQ%AlZLbYx?agHUMb&KPS~O}T!3o3C|oXv$)#oCCY3CF_g)D9zT$5ZE8M CsZc2Z literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/on_body-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/on_body-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cb6208e919170ea18f7aa1d857971c000947fb2f GIT binary patch literal 262 zcmXxeF>Avx5QgClMGbYw(4|XpmUgK%Uly07rXEs4a3>E!lI2=N)(J_b7z)=N5cuiI(F`+zZcaCBVWJQw7prA1;yOcjiq0rD5=e%FF<@)~Nw^|o@M6pQc R+zeNX);k3&&9jj)@*ia)T=@V1 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/reset-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/reset-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7e9b52f4d349aaef95618e0663e4c9361c4b88a9 GIT binary patch literal 253 zcmXBOF;BxV5QgCn$gP^SVqqy^p-bcWx}*XkG89!+I%Tlz^g=8gpJh8j{Cf-;Px|iB zd$+p6=JHA%z|sDkFb;HUH+os;YmWgV1NK(c`Qv-joB=Kv9NB;XXXyj_r+IT=RRx)w zl+hi*!_1we|C$^?vZoPkTtQYk>0@XYur7OTu+Fzet73@J6$$#6i!@2_-Ya%s4e*ji z9mRn1rtN1Cy{Az`sSFD0MMpL!IS7S@zB%XZqRyAkyT8{mOWE0+neM8)pR+#5kJ7vt H83O+W>UL3a literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/status_code-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/Parser/status_code-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f98a53ee4ac09e5c9bdcbc131764f4f18531ba68 GIT binary patch literal 265 zcmYk0F;BxV6ofk6F2;lNVy)*p~ew#J|TV42&n; zefM2#&agebxDMdSejkuV*SA}}uJfx%lIAEn*CPY=TGjdeThkl?P8hwj5dn@eL=1QT zn|oGOkoj2|-8r~f&<7blXAh8m<_RrrAS=BL6x$VCmV-7}=eI_yVkGiK_~RF;lJL8r z*q$}OOE+l}Bg$Uek0^%VCP7je6mCeGmJ&G%g~okx&f8U;uOA+Nr)8Gpvqd)Ls=Hpa N-d&iac{Vae{sX;JR&xLV literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/body-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/body-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d06e00d47cc48620afbb516e32e39a4edf364917 GIT binary patch literal 233 zcmY+;!E3@W6oBy^B-ANvFc=eW@vc3;UMky)IZUL~lZTMB=?tcQA$eu&zh6-=JAd%w znlwI zF<&ZN1`jZrLuYzQV3vCoD4rhRF>kFif-juan=_H$guA;A`l_Wlc9!JXsK)l+QMLg) pNlH5-v6VIUG?Gzjfgc5X}MEj-7@^L7)Ia)JKp=&g+XIZB`d&Ks4JY#`7$#^o| zYh6xdTkVrfkd4fIk#imGS-j=NPZjN?$Riym8H>a&N=2c8T15%V#P#fs*XsxFyCceJ zBDS|JuV+69et#ScttuuD;a-0RNz|rx;P#OT+Y4M{Rk!JsRg&=(R`KL0bz&;EtefaL zm;MAjj?%HN6#D$P_vmSZ!kkT7$7NNLA2XR7GH%vChnwlR(DXU)1@34aehxS5XudqZ zSVI~#diL;;ggg$JbynmLVR(P&o9VGmW*cwNRC&GrvG}t58imWKL)Mi0a8&N8*nigb zKhCH@L64J$=L!VDq#|U&Z+L-=I2^xec0x^R2Cki=mN9@@)bt!+0n{qkHDa)QlMG8K zG{~22X%EanDfypRGc-W|yxwD4pRJ`hMaLlBqeM{jctb!&tsEnLTVi+%+q!_rDAr{DF@O~f BHc9{h literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/charset-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/charset-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f737ba23c1186c720694fe7d9e4c75b58a4ae80b GIT binary patch literal 339 zcmY*V&r8EF81*38bc&ZD=sbjY*+5*+UoVwuv4_c+^;9IJUAhL-BqS-a|K7~ngV*o< z`rbPof53G6tSf*gby#!X=v^@tql{cs4YQ7W1n4Er$m})GHvn7ij8=}{4`__i6egxC zrKmK_daE_FU!4I6zFo_eAHyUu%z9TK4R`-J8)n(wGSi^=tO&Ve)#qYeWBZqe=c2|; z9TphHD9^}kV!7|E!o|C{LhT>067uti!Ff^($un{zMY(LeH_O4~(U!lADABF(wBc+Q zq>k2Bx74#za;j@uY30Mmj+R{N? nrM;EdNP`^>WRlu?{K?DWMey1G!9gj_{IPPx*ed_wRZ96UNjOSr literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/content_type-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/content_type-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..474f14aaf25818b8f81cc49b8ada682e4189db0c GIT binary patch literal 353 zcmY+A!Arw16o)-XHXS0u5JV55Ui6^r`Sntn7JHbCQBOre+P<#Avshkch-2k9d9d^WiWTW z)NN(qdW=~M`sy9PklA-=!W8DI6BK;OEZqF}Yy^oN3D>aIS;_MFAv<=WkEE^lkuY^c z7V$sL!u#X^v&&|D literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/inspect-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/inspect-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..47a97857e07e1146e087e446f893f17d3d6fd42a GIT binary patch literal 300 zcmY*UyH3L}6lFkep}rS1&21MyOB*vp2N&_mC+Jm zF+^>I|LhzvsxR) zl3SyzbrYjokMyIj{uDIBR!80_vDfwxc;`M#L z-sd?Szr%F>tSW#<*=Ni(YEw-4C=E_q-ZJ8P%@Ckvk_I;~dA)Ji8VFO7D&PMf6j^;x;0ccC^{;9_Fa}{OFU#_Rb%s; zh-bXURQ7X>B9y1WWo(%1jKsy8GhA-(vE<@oz~DHpxnOB7-6hh z?nuMv#!D@!jcSRbrC>zWq*BuPpDihwP+wsf76)lCn#~7keCEeE+0WoFNp-%f^Qufs J#gm}chTqH%ZY%%* literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/new-c.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..9e1b57b93992a9ab7d9f7f2e62a47f7bbf9fc59e GIT binary patch literal 278 zcmXxf!Arw16bA4eq!!C=LliF|Cxzm2ej-%VVGk1-*{O$+w5biIc_m35`|oYpyghil z-}kMB^wUeFe+vKATWi$1i*Z={Gx+G$#BpE+_9lu>%f`6x zAX<;Th*DWCuoX4BIFUgpZSlYus}?0?_aVwShMfFr9}K#j%;(db6NSw&C!;synK)w~ b=8PiSlyv#uWG+!(pI-k&-%I;yWeDsKCpTIC literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/parse-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/parse-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..db1df9d482d83a7443e3212eddcd2de0ec85bd66 GIT binary patch literal 591 zcmZWnOK;Oa5bgoFB`xAokScl@xfgnAeBKCT3W=~pN>v3eR%EU1alF*tv1Z3q`S)Gd zi7Lu%H8cCYW?mirQm1#{s8H&Q-7ZmTD$`SQn1qu~v%^3I^Fvf-ZF@$XCHESp5fo-DrFN!&p3^*Jq2|sS(H`l;{<;p0>8ASxuQ-32h+=AuWP=i)pUVbandrR1jH;|4D}GZh%dw${D2md9 mBz*hPC-MobX)Xtd_{^WdoBaX!%A$BbF7sya(|m2TbI~Iqp1rpK literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/reason-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/reason-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d9ad98ae0c906a62e3b71c53c845c86f492ab8b2 GIT binary patch literal 323 zcmY+9J5R$f6ona(TZmw)ka!GH7zzV4^UV?jL}VyLQJ6AVPU_Saj<01qLi~F|+77Je zrSBZiKVeb6U<>f1f7aX!+|&y>%cH<@=1>zLuUQ^ly;W5KP;zHbJAS)26Ov^Rn4wX! zMY!G#t(pBA48XWL^j!Nn1gT-xyP6=}{Ld83vaMxCkmRH$c@%#%o=F{g!NX-a5j+&a zGRK!;hj!BK9)cvKg448 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/status-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/status-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f961d3724adcc7c34095d8d9f864ca1d10eb5231 GIT binary patch literal 237 zcmY+;F>Avx5J2G$L72GEKq1g{Q}@R6WpPPkqM;=icgi3nM{Y!ApU|Dj->+%1bbj#h zX4w}!)bH2=yfLTa!e>h6#D+%_Aa;$Ct9{cP0BT1O2XZgBxDl0-q81y`KpsaMe2egW zr9Mph86&{tj=dW=gS?C;F&*zC7*(~>oap)rAvx5QgClMVKbgK%h`M1k}Cpd|6!DnrdhW#+@<<$&nLL*(Y>o`uAg+49WiS zeD7WM0}s^)HUMwTX*c(ol5=9i1L+3$PJsBVm0W(+^%kIV6tO4wa=loKQb|#XwWwhl z2OE5Y@O(zUP5K=o!1yq9uICJnd2&5_}66rwY9VAvL}VzcsxW1+?Bvo|II(3rp!|ChLI;)` z?%sR)-kr`rV7cF@0$|A#{$%*CER0nn9IcU+ zLxiQ3Q4MvBOQfozg=*aZYbi&mzQZugPf~yO@HkrItKkQi$M(Y}DXym;@5(exzDQ@2$*B>&#D)q}Uk zybs=+)A1+Fl2Q&Ss3@_P=J02Db)v%@&i4#r|_5TxXQ^P08^`zN zMr|#x47J>0E(NEG7o^-!*796P`VN91JBj_#{lnfGUJMU7|C>HsqT=$ncih z_kHes!({c21;AUoT}Z01%qI0H@yCSRFkl~X;@^Fy=@MWiO^2b z7*BYHblq-P$Wpk7*0qv}f3NC%RuOfxBmPzAJ46s+QxmVGC@snGwZ?{%$d%-{<^{H7 z!x^4Sg}*@%WTVVhc86Z12LTKn$EG?9-Nb+T=Q0~o9jwAj%Rb>oH;F%bnGQ11wO#M( VxSPGi#qEBCFVu}tb0v%k{s5QUd4&J~ literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/to_str-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/to_str-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d74b5512ba5cd78ef5e274bdfcba8e2a263a2349 GIT binary patch literal 272 zcmZY4F;BxV5Cz~4$gPOjDkMN+FbiFX=j###M0jY0s&vX=*@;6e9G_)7LjCsyHB8L+ z-lumLt0Sxruh;-QyVFjm9@~0tmYik@MNEMJd8;_ReXptyfP;=6UDOZraZAb)GCwM7 z8iczuw3Fd$^Z=7O4%(#^WQCU@#d-mkMQ5z$^xhhk_bK^2%w(>xJv{|Qwxj}9;9!#I zwQP<1jG_xTh$NNO0z1*5OOqRg(iXoNWA%d5<>ThJ%IVENdR9wLul^pGqGfY^-n+*z KNc&=CjO+(lOIRfU literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/Response/uri-i.ri b/.gems/doc/http-0.6.2/ri/HTTP/Response/uri-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cf3894ce29f1a10f9040747a37d6900c833c868c GIT binary patch literal 231 zcmY+;zl*{!7{+l2Da8s3!pY&5+qLuS(!(E^L6Op%970mlYq+#;NZxY)zV*lA^b8Mt z_zvSAnB-e50lta+Woly1;?A20qFuq+{7@8UfLsTMZO~u$XC3W1i}HR8NL;6^DG?S= zhT3wm-klB!LFu z%JtK8567!y4G+r~%>X{Mt*M+!>KwTjNs-m5NF#|cit4o{bN7u3?7rDl&BT%@BnuDBI! zd>%aJttpIF(8;$#@**8dQBC&Vn@P*uv#n6Wvs~B0mwQe(LhW3+wYn}ntt2n?wq#oQ zV9J#hm-;8eoeXy~616KPaglad6G@{)5)wn#94aYT;4uu0)t)oYH*MQ9R(w;>o2E$n zLOD+rmbyKp!GSVX=CHp1AGQOp%qC)l%3*&nNFRQs*Gzu24W;Iuwg#bHI*J-5wMqzvjvKmWr;q>7ZkS|8$(oW_I`-)n zK3h=Q)94lGDXc-4TpYcw1mSh?B*Ejt(RDzzA4FJlotD4~BdF4Y#5&b1t02WgnxoLhvr03lunWRr5RQUm&@U%(Vt<(1%&b!4 zCJr4nZC3Hz@D80e5;f!+ioP8;l7AUjwu$`-7sjK=dy{rF99trs^mS_LAR+s|3>VhM mw>Ie;J&q!A`5-u@H#nIh(RJ)!+TSp4R{8AwW7k-;75o67ua&(3 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/HTTP/cdesc-HTTP.ri b/.gems/doc/http-0.6.2/ri/HTTP/cdesc-HTTP.ri new file mode 100644 index 0000000000000000000000000000000000000000..0e9f222770bfee56f593b40f77ff1f2a19189f70 GIT binary patch literal 1550 zcmai!-%r#)5XbMqwDmYR15r*;JQ|IOiMG+i#I1=F5ki9?fjeLN&}`dyXA*} zy}RvkJ)nh`ChdOb)9=je%p+rrR*!zL5TOIc6CCfesECQTLJik^ygM2lYDnAO0o`V3 zz0&PtepX}%$)F-3sW8w2WSEQGTVsxHIEJS&^x~%W5OaLWaW>J^v1<+#d6-XF5l6#- z3<=J!G)EhuE}YPqxaO0X2G&G~>;n(V0~=UEg+C!UqUmYwpKzA=0tYei*@+*rR7fki zACQ<`*i#=Jr|X(;u1OXy#DsDB4-3lDl0^6v?=0MivG0ws0-V#(SGeZzj}L?s%nA1e zJ0oc`U~L8nCzz%x%VyzfEsUuwK(p#)t*Ywei>vHGBH^6zyqP$d5miG-n{4B@%u47b zeK6^SCgdKA=8QTMS~$X)Xlv)IhJZggYw=O%#xiwNT1v1!gK`p4PC~(2Zc`29m#=DMNAf1h0pD@WXKE)PbnCl4H<+*~nXn0Z*s!wf zvD2&2z2DnM$L_C#3cFlk=f2%Q?kVIR=rAhXdb(?N!x-ne+B%-$>1ZJcuq|X_;WC@+m`|MRnjTmCwF>YM$JxOIz17t#tLOg1)qJck_AL z_#FkOg1UpG>lFTxUr z){q_9SEloUcY&R%q|7G|Ay`DweVLyhr2vehiV#CnOfgI7B+AvQx!%R=E7wFoMW>|5 zid6i!+y6^hbT}2g`~H|=mcq>L8?8jYg{5^S#5Ck)Xy?|c0}rxq%6y>)i9-HD>AYXi q#ZZ^A4u;0KqM;za1HfD4Q>J5BC4ZEYD3qZnH4|e3m9dZVAoUN0CwylB literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/URI/cdesc-URI.ri b/.gems/doc/http-0.6.2/ri/URI/cdesc-URI.ri new file mode 100644 index 0000000000000000000000000000000000000000..7e905c7217cb170a0520b5fa7d9e12a79e47d3c8 GIT binary patch literal 868 zcmaJ<&u^PB809blBW*ckQY&?e5SQH&cAU{9t7#&kHC>e@%fSa^9Mf1e7#Y*7|NU&B z?V7f`m>=)^p1<$C_rYC*)8(Zg09*@MV7?IBhEp_TZW6ldWnu$+Hiu3mz6K}+R=0j#i8HL^wQxUs9B;PcDc8!Yjy#MRC=a1wsMz~rtHQU%K_zb)LKf0`47=f{qO27z74n&tgu~Uv z)$Dq@*=(ji7dNTCVV;C%S|9*kBT>{#VZ|QwH8J#|L*CFiTE|Dv{Fk%$_z#db`Qh0! zo41+&_}vfbw?jVtc&}IQ?jR=#J;HHa8wHVz95ASwj5C5h8thZ+3QhO>eQNCLRQSIS zrf+o6r`0biQEL4S101*9t@SUtJ7jc#yzT}kl@y8+MYm=Ra8yZlj}qkSM-kp;FsppxkE0q{;{)-i39y4Jbj8E;Y_d6=MMU$570_f ISM;9pzoY2-vj6}9 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/URI/decode_www_form-c.ri b/.gems/doc/http-0.6.2/ri/URI/decode_www_form-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..20fb41c4be0ba9f3356ad4044d6dc5332afcf88e GIT binary patch literal 1204 zcmaJ>QES^U5bndsvKGc33S(@HLmf@KCQh1A*c?)_(Uy6%qh#q*2u8M**hGoM0< z(W#n%pu0N7|?(r_!wqA7OsyRLm|D z!M0>~+u~L|@^u&|8cO;aXqqBnY7!}$cMYtxVRJMx#aB6tbQawsM^r?hn8}pDn@Z6f zbHWCI|kk>R61=`>xYRDN? zkTbKY;HPF-6W0=AV^X)-M0uP=$B}B<91fbXne&sT&V`|Oj{VuQsc47=mxdv>ZnUf# z|7${DFAH51n=qxH1GYZs5*OWAwLoc)^<)iq$0H6^IrN?q_<+#f@jmUf_k&)C94?hO zPtmU&9({YgQy7hEv{r}Oacx|O<+@$21H0d;jmJxvPX&xawU*%l-a2$R)ds-A;Qc3~ zg7v7*MwHqFE3n$DsFM_aP#uqu{rDmKJ;0QI2qnE!(k68vfn9aT-!-Msf$neg_1Q+O z7surU+>bvR>2CKY31=Sp$ddp&z@*Ip8`E~9Ze}WRRA95Yt-hQm#*Z0|Y!~=;Tzx|W z&U`t+hR3N8M*9Kda?xtFMq3`)KEOFXEV$P2m8l{@{J99NDq6Ed2K?J?bLic97 z3JLjN<)hh#49Yr|A^~!F2w5<_uS-H~VqI9TJ{bfh)250XAXnctOQzXQvoc5iNrXc8 zaoRP)JMqR99#uw|x6sOFvG4j#om*cZ!YCji>_rP~PT`xAdsBpJN zg-6%`UN5`p;Pgx6uQ|6t;rI~r2bBBn`v;A-1aX2)NN#~j5l?bs%1O+UeF=8yNv*|L z$DPazpb&=UoTWnTDw=61s9~|>6fz568H=l;F_+MIo)`5(*SWO}?%L_#%pRm~3);sl RIX`fGwJ?}mKw3-geE=cno=*S( literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/URI/encode_www_form-c.ri b/.gems/doc/http-0.6.2/ri/URI/encode_www_form-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..3f3bb516e5d83815f30033b47b96acf9d7822886 GIT binary patch literal 1589 zcma)6U2oGc6x{>rHU_*f2@MdsWCAv=O^eXba8=X|R*1AtXzSpinkpx88?(gD9A{ns zJ=adUkFE^fBF8@G+;h*p50*~I>d{vj5V9*KU8W-$_E-6$=d3aj$dC=jHXuIz6(I=6=irNnR9yU8>IVln_ME6DIT$S!t(K>8$@$l9#vd{Gf`C z6iuT_bGcvfoR8m_V2Wx6Cr1ahf-VH31461P43$h^#4nhDEhh40%dIpky*sdbF%@SA zT(AY%d}yGtu!CO2GZ>Zl8PGIE)l_pS>X$Vvw`OQ+xr(Q>mN8^Q#0h~5_}=RtY=a^6 zoHsX=Pyzd>1$Fx|1L^-}fwsEZPfB{MtYzuB&`b#$#}mjimSL5iJ7ek~kVz^98n=;Y zwRsz8*>espP-0sKp=6nOry-Eyf+-C;Vqo#O7=av?R&mXetO}XDc`qp|>G}){XAqz& ze2*TL*n9{RnZuY0#FdaS5f)9L8Av2jcpFQXijO#!G=;mSSCH^awC?J}80x~tu~sNA zgK@-z2q*K&v#9n2AN~*O-aV-OE7+8&*vOub|N5rt^Om_hE8d$&bJrB>(Uj~j9{rPz zJZhVaP~Etm|K>3>OYNR!Xk86Gj6(UwA RcvkG`LsLfFm0=#U#vhgf_$>ec literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/URI/encode_www_form_component-c.ri b/.gems/doc/http-0.6.2/ri/URI/encode_www_form_component-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..af1f0955a1551cd47086969cd536c4edc1bb38e1 GIT binary patch literal 737 zcmZ{i-D}i96vg`>ac#w?f}kRo6tQ*lCB+A4Uv||l1iG^92NYKblVq|Pb}~22OuFb_ z?@ZQKRQj0AnR|cd%y~3elhef)EC`v%A2ViZEH|h8aq7QjvcQsM`~5zvP&HYBO^cFA z;}P#_n)+w!MM}uSs*yKck(0K|1uu}iJS>?}wd-0!?8dIKvj*g3+)`!q<|&d_e{1Gc z(XFCw?Twynywrbx)f2&%-!ch9ZPXA9!g_HX9w~3 z>R+BumY>rUbW00%;Sh&FWqBvmfTm_jyMs43H$Cb2*&iUk2eM350&iNuTu#(*lz`Rm z72j)PS`x?haiaZYglZeF7IAGF@gb&KW5N3iAy%QaViXD;T7=N$qa&v~>y)^Qt^Xam z*qniT7906!$(Ri|jY{@F8G`=!pBA_=|KDCBFd8iS9T6 literal 0 HcmV?d00001 diff --git a/.gems/doc/http-0.6.2/ri/cache.ri b/.gems/doc/http-0.6.2/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..1c3438c43e90b34b5151311fc9408983c8ab3d28 GIT binary patch literal 5139 zcmb7I>2KRM6z_+@^%cj-;xxT8ZNsp2E!v?d2DZbzBSAGROOd$PhhPwBiLup4qDE3l z+x+u;ymVRC&~NrTsCWF{L4MY~9-|RXe8L4~{Q9oz436jTh%Y**b1*yWxX$=j%tPN0 zUv_4$^X==|>-aA{6+Bff5{C(%M?})4@L1Ci7^BR7e*0A5B)}}NRIvY+mOCN;X5hAE zC~NCSxXzvx<|$1$DM?Rnxz0p$;Ul8VTCe6h+ge2jj9Z^J50We<%(yd??%dOYM`286 zA5sDV4{$1ocI~E=7@da6A|isyh=F6b>l%NY9{*({(RN&J)p075sjceBPZ$SJNDwkW zg$=A^eXqY(un?M2dW4e?mc+}^y5~A3{gzDuF9%5w5zZ~Cr0{7U$UQJwwQ)5eG0{fo zD109(d`Sr1PkYxApCmJRBlkg z`%=bZs=)UHa*ne|cr*tJ;Lbq044!Q$Go^=p=q;SG{kgUj#J{OB?2(-M7esh|gt-JD z2tHaP$Rlr6_;ywJoJJA7(&yAHIj1bvj5}4GrSj2yyr%Sy=T%l!N-@K+(b=o97=16Z z1Fqbya+pb=W6Mz8tG!f*z?1^ytm#h5MLrj*+1p+CbC{>f)B1gMra$5MI zqhiFlLbou~%P*W?XUlKOgWF04S3XnN89nERNet)f%mE(OH$WZ{{s2T~qIWzgW zS2mI>1_aWoHM`JSLeS{TM^*r|w)M!dxK0giEBt%0>OcH?Jnc*IZbB56ryJ#eYYNs1 zHx_0Wn#lT!yPvZfYs{Q{*xthmb6uw?pCy0VI$A~Sf3i@x{6KfShUEmXad-ynLw}xy zQ6T@h&ITikkeluccE3Gwl~@n9jDSdJcvn|fp6M8%@SsKo_{6XnnC%3#NYbQLqt>-d zldZ-)K=HuRn8S3l35p{X#D;mXa~>ukU&2f& zCYchIYFy0QzL#SVB*MRRl#LyVGR;R+4*N4eOQdR|rf_h8L)nX4P zU4>%l6}CY_8s^J}>uh=kB%TM3f(<3_2fEAY0F=!hlqX9!pC-Lxf($EDqh+IlrRfe1 z0);0}z#d&SdMtSrH@4o4JFi2?X zj+07=hW=7+Z0ha8{Yh_WQ$gc$f?|91 z%6tn_sjcbz%PhIjzel>)kl<(izgkZlCiRB7wG<-t3TVkTLz7Z3+Jk>aMfGsFe3>vx zP7IqaUXU864>f2LSPLnf-*lNhdkC43i*su8j?Il4=yL|0*92<_AV~5o@7m$*<0zVA z|H5SC)(ZV69Saz7x;s}2U{a&jg^Sf6%+G}l)d)k!EJ8ELTN@~J7d93>`BjsY%9;HX z3+rJorQ8Ien`Y)$wUq;Ai&`6sC8OCw#s}cn7YzF*LEX#Hf>rh|EihJXEVmC-8X8;c zB3H%}>c#LR@e~bX8e}kO&%T0u!HWoa@m%}algo+z*}kWI!Xrz5t!`L(;C@(rRhdG; zth}knhYZuaU*|WV!|Ahpd$UtfT0Z@{Wmx9tl&*qs_t7hvp&@jflH~OCPaTK-W+p

    wiPj&qI2$aWffB#C7h=Huw1HlNV2Z*#DjSYC}=4c#x9WfBd!}ga7~l literal 0 HcmV?d00001 diff --git a/.gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/cdesc-Parser.ri b/.gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/cdesc-Parser.ri new file mode 100644 index 0000000000000000000000000000000000000000..bab5ea55c7291d9ea18f374aac99060be5e1a4d5 GIT binary patch literal 491 zcmZ{h-%GVI#tAK=Rf z1oFMR&)t1<5pLjW^`r}cS8ZypW{P(moyw3T@sgWP7zF5fPLj))^?C_#)G%^V{FZ-; z!Xk{;8g34h1vg)P3*eA_EgBm_oVDE8jv|eN5QlUCQC3MMNOG-Y{;;*SWiG>Yx;MFJ zL7M4WTDBFul+8!SDx+&=d9DQ06)SXO9k^q;Q2IN?!xTp;MKmJGZ7C|=t3#q=aK}i_WZc*b0rHWoSA?Q+zDtvlBn>0_$nIG0LQM6Q}539d334sY)S)|v_@O! zjwn3~My-)MZiRo4WGtJ`@}}6&btJn09{DgHyL&*<=H%(jZ~S8c-W^ZshK6#Gp4>d` VpG`{ z-SgaX^#Pmnt7!qAr^^AuV7g|bud4jE!(K)TVnErU6W@{|ig2;`#DKk(Rla+#>l469 zI*$(EpZ=beHDop_(yf8*%sWW;6)ix5#}TKnf~>I81>Y=SUG$o;%5O-k#~}nOQj#bS zPO&|!ffr`fvznehz3818MUaY6m|nDI3hAI13d#I%&YMM*ukX?a_kY_(mgKWpJI!T# PJqsO;8zsGv^q&6$F;ZN` literal 0 HcmV?d00001 diff --git a/.gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/default_header_value_type-c.ri b/.gems/doc/http_parser.rb-0.6.0/ri/HTTP/Parser/default_header_value_type-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..88b0b1db20b3dd4c55238cc700d746ec62428542 GIT binary patch literal 270 zcmZ{eF-rt75JoK|ES{h?S_l@YMYo=7R@B23%5lW%ijeHhdcoOENG6K^-rzPiSAQSx zz2oK`&Nfe>2Y6sk+jHM2d9%a87GkqUyTfF@EEP2T6H$P8)=J*KXuSql+mtZ@9KJ8b zN=dO1OQB&AizD9$xSoBlHhq=|P~~OBi5pmS(I(E@BRJ^>PpIS-d3V2Oj;1cvb(h>9 ztL?(*=RQAuWHY2N8n%wmgu(P-;tI^hA%*W&cc)5T{7;nrj*o~GzeKfH=?p7BsuNRubng;JUHG5 z@9u^kV7q^^3gF%PUYeb4M}vH$X_YTt>-vKLd44I=!ouA}x0C*RbO4iS>~V+`R;80Z z22LzXDWg1rW!Y(iRlYU4c{s-C#H0x5?|nlUsi7!sucJ7kZ1wOJMCWZUqHGKb+X-cd zI0XmMps_y%TNG?r@Z>xxPpf>Xj0|B;;*_Vba${q(n)noMowpHH#P+;q&g+wmI4@Pc z)YALkms5#V#m({|ugC&l%||5BvP%1mu8pQ){T!xNf6 D1;S$3 literal 0 HcmV?d00001 diff --git a/.gems/doc/http_parser.rb-0.6.0/ri/Object/cdesc-Object.ri b/.gems/doc/http_parser.rb-0.6.0/ri/Object/cdesc-Object.ri new file mode 100644 index 0000000000000000000000000000000000000000..0f9d4d07d681558fb241d05bf11fb14d5063a9d5 GIT binary patch literal 436 zcmZWl%SyyB6zxLN%u}VH3wQkh&H83j92E;bKs&1}N}9#FkOg1UpG>lFTxUr z){q_8SEloUcYz(Nq|7JxAy`DwU74RAqyUVgiV#CnOfgI7q|DE?YOZ$ix{g}BbeFD) zxQb3mkrk=<@4A1RvS@TF`VjhKhFJ-f-Z)-jCJrerWSn#`5gdWBcC!I!z%e>fJC7TMX8w>gQ$#ske^cj0MAT+S^xk5 literal 0 HcmV?d00001 diff --git a/.gems/doc/http_parser.rb-0.6.0/ri/cache.ri b/.gems/doc/http_parser.rb-0.6.0/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..63e19dbac4deeddcfc8e4e977947178b3428fe5d GIT binary patch literal 478 zcmaKpK}!QM5QTe?wXLmIL62JYA_!f25=jw6Y%wQ$SWi8K+3eUxc9SKUEy(_PlUhA( zy(M|yyqS49>NX>G3Rn^en4H2*zB%i3q_5BzAE(YDZ7vbI44S^ zjmZx<`oXXNb>Z>NLH#i-!LFqEX|x5aAS?Xv9X6K2DZMU`jBb&KsHMq0z-u;~@6Y}B zbTN6@d0r~*D8&0WeTVf*PtP*@r z(vm^=8xn$bAmHUd858;5H4tk4u41)vpc^$rsulwg+D_=`8(#gyJ`+i{k~9S{W#r$E z!@Y{{SmyECQ^Knb3Up%7*n$we!C92^k|F=59l_6f0{6a^TBK17+q_=g&7nsF)-DO yv6_wc6G~_?VJ!?c)57kJ;hlo;RV(MB#tyfFaaGo6A4Dg}KaLL@Fk0y!f9MM$Uc0RT literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/InstanceMethods/freeze-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/InstanceMethods/freeze-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a9b769de45b69936238d18c4fc266e114480c46e GIT binary patch literal 526 zcmZWm%TB^T6lGxw0vZ>n3tUXfLX8P@J>68JO`2FW2HiBKnU-5RGLL3D4a(PBI*mkJ z-}AcX9Q5As==ENv7~hKT5OgjV(TH{fdypxB4OrNE@B{lY1TN`@Bn&VPM5&2L!NAK& zi*zmD$Ah9u7)>P}8`Y4gRaIbITT~o`?%{z~5T(m#DDlN#%nMOusYsDq?qOsF_L<*A zKspB`lTS#sX8cQNVnfok39GyykKA$dtu%|B}7x+H9j{+d}{tcXwteN zS|TCWC{uC+qL#Mic<5zPaiX1_*QuvKS4yDhxe58P1$xIjz==l+icB$$NZ-pSgSu5l zlNtYQc1GJ`W8Mr=PF2$29Zzzq;~dC>ie(wsfq1O9W5hCxQz>-aY#ArOiYCc~82l004lPCe z_a;sdEj@bt=Dj!bW_A4s9iJYmjM4*nw?td2JRY;PXgU-q6#I=H^^O+NbhdO)NI6m( zNn=4~*x}92BQ)?93p%Lkl(S6H*B$Q?^i5q++KAKwrCq0kumWvOys7A$e=#SZ;YveQ zdclj>i>AA0Xbl0<3*_V$c#Wh`+7(;3Uf`Yo$Mc1Qyg6nPS5&akbB#j$1)}2Ebv$!- zfjR}t#9AjjQRy{icCQznm0(Ir-oAVP;p4m^^v>xpY+MMi{*%JIoeKnszc%RmvpbP0 zPCk7m-yPS(CCR~pQxAr{&bBSlm5Ei4Q#$@&^cV3~sL|G1lGq?GE?bIl^GWw*2o)pU z+MTzJuwWdU^>LQ&cO$gH?Xy0&M7W^Mo=zR!50zjxDG_oeuS`;CB@)}VB&tXx2`ToKemsR#Aq_T(YGRMBF=ipY8@5~l6!Hf)-dBvtgUw_hTD z+(O>Gd2fCjlV>`6x=|UWSMohZTc|vl@p0rHmRKtOfjKL?UzR~uAfeYSE-3ltu)+AF!kAKcQf`*lb zsv!PmLL%2$6zF_~HIKHtqtVpD8sd}1p9R+f_2zkAGK$>s*?HGvzac&QMYj>c?4SqppmYf$R(UPZ`vf&imGl4r literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/%5b%5d%3d-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1315f4e34eba2ea260e4ed2a31ea2ca75971a076 GIT binary patch literal 471 zcmZWmO-sW-5bZ%?wIU)#)T%7;q9B^{79oBG0#?Q9DTJ^|Ce7OY2%C)(f4#ej2S08z zyqWjjyjdB(;_>sX%rL$Z?F@7&^Jq+0Lw6X(mkxIBg3z7JfJ^#GQU(~?TD8X(ojO5) zM^%$Dnn^tAX=X$%n+jvY*>Dhgh(~@!l&+%*_BMuKoacKrwTn7%=#<6gvK z{^mD>F|q3_(2Wu(YD5l&q0i&LGh05XDC#e_7+&`a${=(P8BH&&&+yB6mReG zzV~e#gLgc7xz!oQ6ID;a=6X&>yq^SpGV`!^7bn5t6r|?glnKDt&89wUj$<#5v0qe7 z@J!>Qj$}&BswyyU7%K_N4zM2;)Yy`2X?(nnd8URg4J~qSyh*$yIK2mpY!2v?iVD!e zXo+Mi*J!={d%qS`tsc07o*oZ>DGr<%m5997l4&tRib`?G7$PJ3`5dO0{`3@yl4&VH&y#xz0DqHdtFDi=boJ8z@6cfmwQMtegsu8c_&$2(_`UAzBl0os5QdqVI29VHWObgksRYKLXZKx zr{s;N8WHpg_-w;9VQSS>7#rfI;H7r47gkK^nj#>MOI)+#^WVMCOtFPx)e>1a@-L?v zOod)%r>$ZC4ONA#}XtEEDCTj&lV? ztZicqd7MJ2jleoixP*^@bOYiAw9_t!I+5Q^ts|C+y41m5)g)4+6j{tI`G-aRkzkGu zDh1lO#52R};9jM~JJZ}Ik>3|(ty!7!-4xQJo&_8_H>GhnYKPJJ%|7eqT&KpW9eTLp z>)U-gESRd7OvYJLRDYBuuxwW*eJg_u+B>7!?hWs(GoKpcsnIQ^`;YH zSiLk=^s9RH-rLxG;5)Zhm~(z%+9gnlt7J!xV}DWr<)z2H>nQe*mY`9-i%bFMuD0#Z z;eYN$5ua8~reu!%U|6*j_O+=v@Aftt3~lmhSP4sYGDCj&KjubQ@oYs^dh@Nsi~U99 zco~(z-h^s^6&5wqJ?AMy%W6UkOcIlYdshfGGe`{n$(p>mcmIuIp@ez;B@K*lKKZ2C za|a2{lDk%CsGgV+8r*dFV-4C5TM24qff{RA@+W(NoSp`bFH#@DW`d+14=VQ8_Y?Nl z%XjFwy?Z_j3$$8Lu;$qgMJ3r_Vvm`Gg;db_u4H!Zv=83*rESk_)}w+DwWPEJv6AMw zPMuRJxsXyU(i{zS-q&dc3jYQ{?2p`3GK&4_u~U2E+VG%@cREDc^-;b%#Pi$Ts4kVL G>)->`UaW}# literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/key%3f-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ccad5c6a8d4d8e59a5a78d909b24332951c1208d GIT binary patch literal 448 zcmZXQO-sW-5Qck@*ft^_N>Qw^#ET+m&YOd2)j+_CXg!4zCh4YGy1NrL8zugF^C5_O zn`Pd8X6D%&zR}6cJ*Je-RlQ^;$4xZh`=K-1vHI4c)ZK#!G$_%OP7obfU9Uz_k&OC#Lt%f4EyisI@&ee*QhVYD- zoDl_*ksL|_qdjnu`k-IFS`Yf8})XtyLkucw0HM}T7tL}P?qi& DIFgG$ literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/marshal_dump-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/marshal_dump-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6ba5c1e32e138f5edff0d6b446a8102579b1a01d GIT binary patch literal 516 zcmZXR&r8EF6vsVCH#ZN8Lj)B<^`IB69 zoe(Ncx_(;CAe?i-V*gn1?6O(z+HFU@y3kpx3PP0JrX_=dtA$DD8f9vmGo(0Ab9Cv- onlxjspCAa5jo9y6wmjD0& literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/marshal_load-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/Memory/marshal_load-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..61b24829186783e34d743b96720370d9220a592f GIT binary patch literal 560 zcmZXROH0Hs6op+#eas*VqJj#cy3mbQmzhn+$6&z`5p`3f+_tHWljN2pMaExm(h4%V z2?;ql=gU3It1oo>=>`i*$7()hw#G8u<||3KB|)1SL?#f*fCjgdBs`uniTn$4!6@~6 zJwIBIje^O94w^O>yg<6&8&5&c+J;h>(n_Z6DjmcPXlv3T(t}0KBWQTn(A2?bEe(?J za!hK(8L>530z%-YAF3z_tj84>EC~+<&(D28-$J+5^D~`yswhUu zZB{cVxq3HQrBPgzQqC4hl|0>#2YqcWi%7yqSIM|+%z>IMzpDr>j4=BHAt=E6G5iGId33gEuk)**>UWI-hIfaroiYP zU0tGEwPvo;!tl^7glw-2oSVUhRVGCAPxp}l-@H(cJuw>|w6AOmsN6UzB|`oIh1q5f zS&6HIkCh5ee_l)iiMo;8jT@e0VdV1FU(Q(oHFaxAzd)k}$uKA=!_d2AG`+J6bj`J+ z+}+BwW%+@qs7^|ggz~jY3Mr~Y+lmuWB$?paRHu>@nb`WiANNA9e|^)sPZps!>b}98 R7uk8&>8p?xusH*z{BOE3! zFm&9|H8)&;k9}c^tre>aV%@R-xL~5;xwk8Llt$*|IfV3VZW z3@r$|LD&mur#%jJV!xZ&3EN84r4ID!Z7M}ZiS@Y^-&xN;p_uextx)q!^W1cBpkFKT z&NR15><>iMXjWzX*e&c^M>uHZ(8vxY%i{*d7Wsz;cs2C|R@4=p;4u5nfd`3BWB=yQ M-J3qs?B{p-0>wqZ^Z)<= literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/BlockNotAllowedError/new-c.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/BlockNotAllowedError/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..d04b53af8254bc8304406cf3e96ab2f9db8bd634 GIT binary patch literal 517 zcmZvZ-AltT6vcgzIwuH%42C|0f}r3>U(H_X{D6WRqVuUpxoz*Zuq3ynsXG69lXWVh zZz1>OoO6HK>^$@R#~Ug*ztYPQ+Buc!zSv5_j>flu2e*?Xyd0q-@d3F+&Rfl}5wb+X z`A|}^7?Zt{lHRbqHHO@+e>({7CVZ!Aaw!Vp2W`j*%%Z6{cZrQcZ99A?uE5wj?Giuy zt$6?gGXvE;7;L9O5}qYmSOHReAOn{BV5Z43Xrmdv7g$+A+C@+PxD6%f#l6tDL4&S$ zbUQMi4T_~BDjSI}ti-xNU4pjEnZ=&`3da1t#JxpY}Qw}9_JTPa&+b(T@Thdd#GPPWM~^VbqT@`inZW8sqj`VOT4@60VUk7HQ{E{2 zV1?iSQ*LTi-L6nnTm$^BNr){uywS^5!=>5wNyv+WlP&L*>DN^YU`6y90SwcYY12`n z5mr5Gzs>=&5)Fw^_aWagl z*Ds&?Su`l!KwT#qP#=cvst{OG;;=ySjYIw^#g>m-tqd;>uPlQP`>n<`Gu&OWXoRve zOqP7dmh3wq8TD~&qesbnH}*TH{LKJ7+kU7d4bY3f2JU_NAn8FCo&EXRmSpRiy>w4Ooe@6DU_-YegIzBMK1S9&o-H#1eXOB*8YX?%}(bT<<5dKN^+*xb@{V=X4Viv%l zST;0OD{;&!Y)aG>Xve}35g&dlUKXk_a?I2+oK^MUyDGH9DcW)8B($d6D~xx&lR{0b zwloKap~(B`gd~diNK$d3escBC5Pe>Bxt`l%sZLU($mKJHiuAO}C)TLkg+t_Kl9$HA ywQKSMrFl=1BwO>F9sjO!wlaOzxjR|f+xN@u{X3g4-Isga4IYhEAa5izP4WepJF+$a literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/assert_arity-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/assert_arity-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0c8a86640589d97f6caf618526c15cd61f378cfe GIT binary patch literal 529 zcmZXRO-sW-7=(L}SZgU%iU<{4qJko5&f7~`Z6IJpL{FiFP4lK%x*y@qrqcd;^HG%A z+p;`6GdpwC{-T4A7rmf#tTr<+sg8pIKlbfD%X2^zGUR4sQETe?_QMRM=35pCptOM} z1s5^k^&UO4JdbuWShd09`rQ5+-KeyvL&)CwMHj_ z<=Z#oIt?)?5Lu@rbuhwnvIW%E$of1GnFyv2{>M)Fhvj%@dxMqN-r~F|{Y|4};#rg%IzMHesbT;C literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/call-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..14539f084311fd1253ad61be863062b79d0dab95 GIT binary patch literal 539 zcmZWm%}c{D6yHIzPeo*S*$$yY(2Ew28A_a5C^!+BUW$~oeci&6rlcuT|9abIIHtG9 zAZtbEem2PDn*wO2|xy^l8qtDT09_<9*Bv(`>0(zCzP(fP4ox^qAoc zHdr>|kW@o$4^7eHAHhtpZ2iPDXsKy$OL9ozlgV6wz4&A69dyJDmu;(fZOOyP=DMtN zVLZV%w>Z|o3=~^0wS`InEy#eTN=s(ko#dEmFs06Lu-DQ@ji*OD+%aW2$F{JBt4C8V zz<16BkFIRsy6tML^?qIHs6o3_Np8Xwu!LvJB22ZCp{Wl-m4>m(Ox1T0Mj+J2b={!l eJMHs}#>A+4=gFSAYVF0R_8-r6AaO5PQMf-lh^j*X literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/cdesc-MethodBuilder.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/cdesc-MethodBuilder.ri new file mode 100644 index 0000000000000000000000000000000000000000..005f6c92e68b26624fd4499ac0da4a7f272ab753 GIT binary patch literal 732 zcma)4O>fjN5ZwcELbe|&pdz)Xsw{DZob5~0(n>yTL8U$UU^&U`uEB{T$Js)EJ>%@I zmZcYzL+qJ1@4Xq%tMrkb-hXiwV|UIs+Fo1T_wubt1${Gvuypm+U~CPZFmiJ%=*0{g zXP$Lwfw6r6CzzjpEq_222qzDYov)c^+W#Cn#!zNxpbaUT7M=E?m&EZTxgZTEt_7sB+!ICtr@}yl{;P zY6-eF?V?w6?-~_ifpT+Ixi+B7UX@_oQ_i!TPjg9RCg?lo&BCl#QRiL2xk4R_*g@ybN(YD+K@Uya z2i;ciFU9LhTZ_Tl$iWXInjgt5)|{Xs_@J~m;rA9I=y~MaMnZERH>EeO=;|&!tsmXM3Tqts$9p}{|bzK$7YRdWojn*W=SU7mncpIJ>KnM PbYH#ydx>YR9xVI;@A2PW literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/create_memoized_method-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/create_memoized_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..46c2147a8f12e5100810c77edc69a22dd95f7c47 GIT binary patch literal 459 zcmZ`#!AiqG6zoB^wThrr5$YjE1iff3US2L~tAT(O5j_Q2Hpxr7bh8^a8;gFuo1`K| zybbTo%$qkmgEttx+^ZB|B0uM7mMV)!ydSyaR3kG;3oI1>!pwqZNq{_rk$X39$1D*D z(8;DX7a8h{e{??*c&OlPoAb;xTWD4; ziN70@$UUF62_5E0TsuEGEogK4w9 literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/new-c.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..53d20025c17bad8a7b7f22d040b8a695e110c2e7 GIT binary patch literal 580 zcmZXR&5IL35XEzlF(x7?VOchNXeWpY!JUJr&Sf^Pfd(U@@ic^?X1XS6(;q`mkIUw- zw|kPHac@QUuU@@Z^`!rkj=tZSlG0oKutc{tJR6CpEbeQ(k7)FH#p1~ll@WU=BvN`{ z=Bn0Y3TSMw*9i}x{*JRHPy*_8YfrX8QdK=B2 zWf6-%GA*0{DfUP}6I1-c(h+A!5ylcAsxyS#7s0W2uzDmqm!NlFgvOqk4T5l=#Uxk& zMY5>99q*p#R_Xh(twi(j9J9}lW9a($eTYfyMZ#wTP_g7idX5%*|AfBND$%ZIp3 zExOiflC_#+<&E(5|IEu2YC&o%euKmCNe5{qB(nI86vfRUX4tzgL(sfi0NM|>=;$Oh zO1ONBz=hs4d1Z~tU1-Qnm6t|4zxgIFP@4NBNwOY`-@f~sdHQd<=_$zj&gIpD#jnne U?VlIr#o=;aja48&Nobnn5B4H$Sw{k6;HzKIlaWGgMt+q+o?!M+SfHK%`0h&;9tM~n23tE z7v4AD@B4nvM>{&*JYh=dgL5{SsZr!#qE&lkgyto<0y9F%^EUFAF_fr2h15W4+;3Km z(izyB-ycG9R|Y)%oBDZ&IxMbL}(;w8P*sfB_Q8G0%b()R5dmXDIA6aDK=KU9Wz z3;DgjN7Uk$W?@Df^@e z2aLPgtY$m|efCe!M`4I}OU>5QfWp)6(>c|vy2RKL)B>a#;hmtQ+Enpa;gijoXR7H^ z)3QMRc8ntTbkPzzrU2)g(&;IE^zx@a<5aF5nS_Dz$Nd|}fd*4+>BP0nAh%)mhHN?5 z`<>YjXvv(Oyb19*$Qg&oJ?AXB7C$EJvGGTe&cu~Y+G#IPf*Dc(&6r$PB-ct1)2JgV tC#jOgE?$uYxO(?IFCIkh@Zz$iIJBw{HuT!-Fg@zTJSimmEEn+sb6q40;r z90=)L(+YVC`tpC9X9WS-FEp;00Y%Qc$T`!?svxA!uLMXlB71(pv?-&pA{X15SEkuQ zvm&>=-N*`^**h59y1=4zG=#S`uGzvxcYWoHyVV_@cO2uIIhoev~_}d9V91R OdoM~0#veH=OZOMN)1w9e literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/visibility-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/MethodBuilder/visibility-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9162804975ace4f8bc11d0c31c599f5fafb65882 GIT binary patch literal 445 zcmZXQO-sW-5Qck@v{q4+){7oOM6j2d^X3w(MgmsEk5iCkx7{>DcXz^OQ>nk+d=zW( zHq1Qx&g`?-`yhkYdz=w+tJhOuGn^*_=*Hgh3JTyL!LA+RJVdcKnhJ&R&A1eVwCJP+ zITz;g4;wg9L=JNUD`o|f^EQ0S%(Bc0sWz2LXxk$PVa|*#l0K4)UFL-uwlFNuoM1n3 zVsHE?tZOsjZnwCYHXSsu0L`SUn#-NQdH)wTkxVb2K#L9r{Y~UBG{TlfyUE*Hag?9+ z%kXFmoP;a~ck_#SNcv$4QpDbs1b(A_O;ly=jPlmR*zkt-LsVdCCfFSGqM)fkMQyE) uVoGPIZ6%?gTuA)#eLv~MUiW&`TrsRvpYG_b+R^N+mGq28F?lChQTRWwMUW!^ literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/cdesc-ModuleMethods.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/cdesc-ModuleMethods.ri new file mode 100644 index 0000000000000000000000000000000000000000..dc4273f4051f77d1df24d64749e5b1059415f0f0 GIT binary patch literal 736 zcma)4&uiN-7|mhGUXo^IWwg-I8pE!uFTF^I8ny;}NGWS`(!t2~mqtuKj3jTRfBhuK zZfNLX_+a$D_r33XPx=tA@#(Lhy2kiU8_C2@3%kyK)Px@oKi*7%fW|?3H>`)>=8gye%sb`fo<28JT5t;y*-vLZ9|w1hK)`giP~e z&->36XhfqTo%R-j3XN%mXKhyrUi(22UbIF#s2w!@ao!sKhdBs`B0b{DI;LtETgjY$ z42Ai|0K9Rt|Wv5289JPngMiMy+v&kZC+HX*cu7PGO7wO5M waL`wzUtXn$YZ!Wbp6l`D{0NypJB%N^XRZ~E`6Sy%+us1nj}Oyd*6%#ze^_DQ+yDRo literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/freezer-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/freezer-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a4b85793224107b26f5123c946fa7a933b86df54 GIT binary patch literal 424 zcmZXQ%}c{T5XF0tZB0c`A|CV*QWU+|oHv&!8VDGXQcppaO)_bg?iZVlV*h&6L@mYB zz`VzsdB20n8+I3us=)YOex+b*Rc0<5C;m}o05)I{Mo)3#U#B1x+t8c?#;Gb>4uiXy z{Tf3Q$9SsSoU=mViy<|oX5DIxyA!PdX(xCZX=-efISOCydtRxbD?@dS!ov(DzPA9| z8tIi#(U#k8g7$XTmj41CIF;*XCSjyP=O@IC%#f1J3d;FA3ehq;-svY1)y&g|eNYQq z5j#=EI3)fRXZc+G)t-yKH4#0e=Fa53JBXBEmefE?CRYuqj1t6dIT2NnLP^`TZb%MX ieFj00jS_!+bK8G$)^R=EW7)0a;(Va;qKu$?kb`d@gooGw literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/included-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/included-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a9501c27061b38ab5329b8a37f56e930941ee11b GIT binary patch literal 567 zcmZXRO-sW-7=(L}wALzA1rHTmB4WMRoVS-K8Vnc_sa`?}o9vrr>3)RG#-hL8e3aJe zb$6I&X5PKtJ3f7TPzlC&@+$z7DH@)#u5TYQnedVVwXpT*`Sx`HLa}cWbHF%IwB*pr zi_492YIz3%3~;6ahtp{NJfb1Kq_77A8Gr%w-HN0iJsJl3o}63aY;u#m_ZPE`xGoeT*jgC2(`o0u0Q&_bXrG3?#I@XS-K zi2(wXNCkKdSmjU}wlUcnzo#f&K9LkRxV=|XbRGPKSVpm)_-E<^iwG&gnp&@4ZvtR~ zWKvKV6WDQLE*MhQnsZn#fEWnILZH>{+lob;-c2{W*`1ox-0}_-FQ8Snm4w~>!`*iT zR=G$)ATf=nr3I(AmOgM$Mu3jEvbX2NgksM;rz9F_*0Q1zs~QUHxNbyLp)H3qqQV5D zIY}2Xj0I<*DhEOyhclk4q9GYZnDS4{vVw+Z?q6QlBv+N0v*IrtZuDPVyR#$RPC|D7lUdkxx`gIL!l9Hy%{PnhJVQe1r z<-PB{@4fy0CmFv#$ps+~VjY0aWD<^9&$muEaLIll;%0~ldiH$lE-+IX=RimxlPZUn zR9@}i9prgrSSa>QHApgPMFOf;RY6FtSaA@#PY&IJDqV&{NzS)1Z&cBxqD6+BgAn=F zMXL>1XMhFekl@angJ%EOk2w{q7baj&I)iQlZnP-J;m4ZCGM{(+s9A>0k{z30pkk^S z@3jstX~!_~Sj+lpLaGJOj11jWDo(Y%Q9N@M=t>D3Rw9A4wv)^otb4S<9J{n&xJ$|` z8n`LT!MCn+7EfD=Ch;jZfp?9R_bN7M+m)Q@Cu`HuhNgnBj5Xm%JNTKVX%P59i m{@Au1?)lc}rcKUVerpU(>UKw4jn-ptaoTqB+8ma*-}WETleW+R literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoized%3f-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoized%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..29b673ff945c1a2127e9f81d4c969f4706f78ee1 GIT binary patch literal 797 zcmZWnOK;Oa5bgoFkF<$E5s1fOaD|itN_}1*YAUc~i68`li&a@;d)=(M4{LW#AHN>2 z?Z}jzyq@`HzHh#nCkMaC{Ksci5b{ahuc+OqGM%&i#GeW(6nmiMg-5(EapEslT>x`V z30bMK;k3t_(-9haaZDz4lXF%m^1AQ5LVeTJgtRn`pwb?YNmQe@CY>ts<}v0wYP{B1 zZ@lm@^%DQXni>nN0+hg{u_y})qSFb?w69*I7kcZRUY8u@%~vMro(hkKekT#VLs4_u zSNx~&H`O^>CiYwMS>n$Mj>bT&R9o(?6aN*oA`0G=6h=3OoHu-D041#;M?C~4092O4 z&m6XzfsByD5wLCZwq;#z$GccK@EO1wg^6(6DFcS)&iCpA3z zhyQ7WHG^8SKWIB%auijJ)5L$rS$^J+?5^xwbVru;6lSS&r-1~K63k{BiY1fRCabg( znRNx3s~_h5CrL7;!hTC#xqwQy>CzX*`xDq!*TJVKf`a%E#9Ytzp%#d A!vFvP literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoized_methods-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/memoized_methods-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..13151db93df824fa0f9331732675c5de771c3534 GIT binary patch literal 468 zcmZXQQA@)x6ovO7-JBvQ8$Rem=@3-J^*NPMhZYM~Wa?9qkgnMpmgJTsRpzg^Z6-4I zdhR{v-t+DCKG0zH0CR-y;l>Z_HY()7?lSQ2G)+6Q#Lz4J;GSt?Q%POzUk zu{WAgQz_}%pWLisJg3T4bjh?)YbS8tcQU4&$kj8Gv;#qZlXD#^8>c_KRVS{$vYxEl2ZHi|YlHAl#1qUnt?3 AhyVZp literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/unmemoized_instance_method-i.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/ModuleMethods/unmemoized_instance_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0ce70de500415a1106cd64c539383db1f6e2a013 GIT binary patch literal 868 zcmaJ=O>5jR6wIMGADfT1EQGXy3YV0mhpexaFG^_)hHfZn(u)a3ww|+M^++@$~weE-}7Pk8`jK&9W)qOv4YYk{~sI0+w^tSgK0MW!Dhk z;4(?WFY~TW3jr9=vGoni|_= zZ!|uB-t&VRdT(gG2;%K5NW)LpU|XZm$ca{Z(V#aDZq{JF3aXahxq=NH?+j3T1b$Ol z3kci<*l9C<`s_ zkfL(6^j|lQiRqoqZdIXM#roI1^SkPJ*PGz%Ke7v0X=a1r9dEq%58)v(lsAB~D@Sx` zj5aS|PP#fnyh1&oPa@)td)B4W4{9CqHK8>}eUQ8)yhAE3APr9hFJ`@qKASVyMRUk* zb8d>RJ0eGFs-=59GSaORcQSVUrgi^g|Ry*+v>pPQ6WMew@tQ5AgO` S=-qWv9`;$i@`j7P9Q^?qjtb5I literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/Memoizable/cdesc-Memoizable.ri b/.gems/doc/memoizable-0.4.2/ri/Memoizable/cdesc-Memoizable.ri new file mode 100644 index 0000000000000000000000000000000000000000..40556b5322ed43b8ca615de903886655288cdb69 GIT binary patch literal 1020 zcma)5&u`N(80`Tiq3Kq%4VW~jN+g8Df#r&Q@x)dXi4L^2TzrU}v#z)o!EFfd_9tB3nh@NT=`DK9F`iWK6GO9z1ct*X}#sw^S(Yj^J3zjE!6aZ+=Uf%?yy zMvH%Q8a=>SfvUJHHUPLEnlWgPx^r~c>hVc7<7ztOy(kz=6u=!Qv(ZTu9B(v7=w2jT zZ^DuIX{X=OIV@N$^my^7!wmPy(BP3Fanl{f3g>vx!G6EEx{khH?tr})*#-OTGvwoL zPHO`LIkJ!=;*$3vb*QoKQPe3qZOvu#HU?-YKISUwQa1|vsbE!Q%cw_PL!#h$=ozU=Mg3oi~f4^Xd55f zxx@L+{qA1x4WGW=s~F>3`RRj66%9^V*Rv0qjCnzUTG)D+dG>`5La{Fralm*tn_9Cu z9%Pz*5CaO28kA4;s>m=dxrG2}dicQ2h&FjJQ26rqpBJLZQj;vTru%{A+2cp0RwyQ% z14Zi;Boc}i91zRVkJ$M?&>bgo^~5A})U>~WT~)C}pun#g3q&E0K~f@(HML5{AK`b< z5iv}38<&YmVH>YBiaE)*5=<^p+en#bl|8tL(t;SL6*zG(0XnxLP}o h6LdU#IBu7|t_4PO&pvMD%ePs4-dyFmT7WlgIp4~otZx7S literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/cache.ri b/.gems/doc/memoizable-0.4.2/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..cf4370c8ed3043779b2be6cff4987ec1d8833475 GIT binary patch literal 1465 zcmbVMTW{Jh6yC$cAm!3_rJGu5L)mjtH}zriG!1CeDbk=)N1sp?8RrzdI&oz?RFpqI zJ2xQEP21bK`SW+axF8{{a!?w4?^cR%RfF_j*uJ9Fr$7~P&Idi;5ov6S4^S+LX}1Jy=Q*_ z>M>642V8X-h!_1CrwSUaqdTKHE(n(z@i3LO3-nn zKrTuh%apWC$P<9IUM()@goc=TL41$V7wr>er&G7Q% zbBx)fsiJvfmFFANukqFB)|}H_jBdXsmURb;OcT3u5A$z{xffs|r&>cl3LXj}#&O(| zmZ$34ds0b0RA6bej d2Cn@fQO~U0$!Ytn{i$`qN&F3BMR{nzeglrn(HQ^$ literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/page-CONTRIBUTING_md.ri b/.gems/doc/memoizable-0.4.2/ri/page-CONTRIBUTING_md.ri new file mode 100644 index 0000000000000000000000000000000000000000..e8109e312a4608b4ba913a43b095bdfad6cfcf2d GIT binary patch literal 1521 zcmaJ>U2hvj6r~8+DHRe01QPIY{*o-Aa|?%drSJUg?@N8A*Cc9 z%TCS2?D@L-VoLp4`oLa@m(uT)+gm3Nf&546g+Rm9v5hC<$we=H44e6__d2sU8aceY&Bau@!8v@*E&ShUBsbh@#OOE`uh1AlXT=R zY(Dr8nw(xBHb;(;C7bir$!6xnmv48)Re#niEH zSdq5TQEc&BYHPIRQ|b-Nz@&7jQV3(P_pWyV=~XLj!-4iXwrD{m*Ulr?VM~&BpuO`u za+Y*l(z?}wj4r+O1K~47Z44$7OK%2JnK9RAice9i#z{(huA&}0oXJ-wBOy#n2-I>~@vOF8J#-v}4H-7Zz_exRdxeAmCdZRYx=&pA@X0ruH1*~De zid1@*JETn%)hX*m_v}MfI$5|7F2J`mW`J=xM5viUgjbOT-3?kuTeS!8f$7X(cJkz% z$zt;b{DHy7i z_XnNuko;2;TZxT95$+0V0bA<&hwwxNhz9~HaUe0Usliw!aXyXB-Wm;AP>+4SIcg|< zlPoQKwo0WJhqD{W>m~Ndmz8fPv~WT`QO^yIB{L7PCLTM+TXoR#f!D*KOz*^T62H4; z48Rq_`GAS;za_}Gq)TU0pdR-NEypWzy{_KKICjMIms!4;i}MQy9=7fDo`!AhUAK+- Us4+QfuVW zXX=CWp*obE6e%D;AUX5>4W+NoH_`Vj(RCDYy-(#A**{*Wuju@{lrBhClFMB)i)Mt^ zKOCzHVXQP!v=-)bqYs0QP6vKt+(!{&jXOEG^XS`~y)e!`Ug+q@WAjT5f`}(0_TB9I z{BcI-zc2Lu*{G+^!Tb6H{Cf4vZ;*%qK8{rt0x{|{tX16!+1sD;N}AdAjO*)*Q}?^S z&kAXF%37rdP!>9AWc3WlFgV$S&>AU0w}1%dNrvDwh~XLb(pYTJl@n@E!&4xjMjgJ= zbqHg1>kh(5EN(zpt7|0?51Nxh;XGffdTHUk>trx5PaX3Q6GcyQ69P) z9adVuSwYD4fJzn~DAZrZ3;BdH2s5UlAztCBKgu0a`-A@=r7& z3C!aX*YgnWDPQFq4p_nBj6XoWggASEk2Fidfc#M~QkIZ2pz9)~Bng3Li*%FF><(_R zFUvWkbWJ&e@*F(j35pWzTLx>w7Ar)KZ)r;TLkLUCGmp7M&=`uCak|)~F@s{mio7I9 zp9EQ+(QL_(g{(=&FOe0gfPBIQl&d&RC#raZ>e-}kkrxk)-mN&S@-!j1c}s$n#VA*E#6Rvzb?D2B;MJpe*qQ}og)AM literal 0 HcmV?d00001 diff --git a/.gems/doc/memoizable-0.4.2/ri/page-README_md.ri b/.gems/doc/memoizable-0.4.2/ri/page-README_md.ri new file mode 100644 index 0000000000000000000000000000000000000000..e5a5546bb0b1ee9beb27ff0c480f352f2e610036 GIT binary patch literal 4208 zcmbtX-EJI76~+;=lTOyribY6}iy~YYBB$+SK`cER*2Er`0XvCoXZK=cSvB2fW{Tgzr@K{MuQAxUe;X^oqckik1bRKV?wtsVU(vFL4GudpPr#}itZ=|tglH^31QKl!QPMQaNP*+KUtLlPE zcQ?6zP)Xx#_t9DM!|?LV=657BRSve2C})RiGr8yJo$EY)ctV9%f0n(RHd~wLI(fAE zBD~9ik=1asb+^0Od3@&=cdo8Jr$T%|#wuNY-5oktC3}0S7{qp{D9>!H^xlAqz42Z# zzdW|%!9_5(ur_sX3KJV^Ghkc0WO@-@UA?STo{2LjU2Wgz!WlVMb}t*%z24I6Yo3DD z(^Pp^>&EQsh$<>GD%0sL4iRT5t*VRLe9jHyR9`n{pNBdlahR(@I(lDzDQwbUvNup} zSod!8yYz6VmJ&1QLiYnkVU+czw`LRLtQ$fdbIxhT_Q%N-|5qD(j~di=&y;G?P?PQXet6}X*n8SZTg1Gg#4PgyK}iyY{k zEUKJ#ql(N>R#r@Py)z~;G0HhA7d~?};)|3`e8JWw1LW-?iDD~|dgGsIF0B=Ba#@m# zg!qX#$Ge;~XGVXjL&jW2K9GiFNYPe9G8BtWA35&8+|=Z&E&VMlM=GszX@n}RlVwWb zy~=yq<=aa9L&D*NUHUr}(vERQM*YRXXE+ez=i-Stk#3kIZ#wvCplr1jPo9Y9;>8Oe z8_dAyi2peKd^ky2Th~XwLafa-Gh1g#aCaw_}`1&+HO5us_?&Fmn15q5mbR1yCJebk7b23nGOTQ zq(kiWVIb=SYbBJyP_mh<3E9KA5l|xRGfe}yP7TAk z9t-7ZsOS+;Y9~_kWk3 zn#|yGVG07wH8voyBseB;Cbfsr9w=Prg;BN-ASq6$yJ6vS94lnBCA;_cF^j0`G{ z1BK+~u-3D_U7LiD&g!bthR4wr_gMq{a|%bJyzCXy*+T#ijw;;-yR>g z&#@3IhyHgzxVAL2c?Zw7V3W%p<@-De7g;{^6?hhZ68|!+93O49zW*MZU&YV=3!9H` zv3VZv$NRV1Jo^@#?e6b6>Wgl(ZQT&^hh12x5(D$wtlC#T`*!KbR7L@2?MyLO=Bw&t zGKmd*p(%|C1q;7-u5Eiqn1B{S3z(v%vqfm4%?N~9;tc$Nz5G=HQuuX3f}Ddjk=^+F z3jTOxs#0cn6C04rr@~+SQ?QY_&(P$9pLtiHkqOwIITG5e<7-z8^@Qm@$Fvt2UE*%2 zIVd>>wK7k5=H(hZqa4s;BCnbzFt9 z&TF)T_0O-DSU|x&EWIU}SiB@I{_+{L+Hb@#8}Tz+V}?MH1XI@vQ}b>C3F6HVee&A0 znrke+gxExj-u9rdBX5lyvGc7EH$>`di84aRDi*1kbcV7bj;N9@#T;cplU~YE_rAop zr4GWIV%g>O5bJ@(=YsFU%9gh3HllZE2=v%Xi{A>ub}s)2j2QAdx;yW6*l}U)DbT>A zSRs2;`#owkHrzD%pdT@x+~g7jl>DG zSyFDFzV30C_>FKNI-YBnx_=4n NXC~N7sG6Sa{|DhidHDbU literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/advance_io-i.ri b/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/advance_io-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7a0e490763bf45e2e750b571751d1242e4c809c5 GIT binary patch literal 258 zcmZ9GK}!QM5QTe?ZLvZxiwGWs^`aM>^YpS(E#%M&MNfMOv)S1;m}HhDt@!UvDS~)@ z?|tvPn0!FFePIpo?7!EP_S`k48Ov&h-4VSeWw?OibtS92CA)#6Nwg*GeRoRKnJh;$CU?DHEe=$?}&Fq8Z6*{P1|1*3)cT{6v~UArmW(~_eV)YK zBic7ast^_w{mkM5>=HDqn$pU;1eS~$ZU!4Bl|?3)k!n%GB`dZ<_Za5XB|$hx&FV&z z4=@bpOp_I2F=2LmW-L{!Ve99S#*d{?ch^!u2crY0(=BNo6NK0f(t13y9M!pf@K zni7SU$gbF@eGO}=c7^Dvqemw#b|7Xe z*Mm&&8H1wHnw;&6oz$CdBTnhG@Y`~JOUfjw)R&#`KHQ!AC3x{!d{&&cIiFyC4J#=B E0LF0$wg3PC literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/current_io-i.ri b/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/current_io-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ef1ad15408386d95acbfb8270a37567b99f60d22 GIT binary patch literal 258 zcmZ9`!E3@W6b5h)qn1_hQiiaDP%nDXoZl{$ZbA+!h@N@~X-qXN=_^UPvH#u_5r*gY zz2En}#3x7(pC|y<&EHn~E1t_#4QVzOowc&@Oko7k*M?@(0!@ofd3lihO!u>YiI3>G zfl+JK5BCz`{Z4MV{q9+w6;HpxBIRgTElgrxpU+O Dcx6;+ literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/new-c.ri b/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..8a1a3981e562b99574486a9ab5dbe6becb1e2274 GIT binary patch literal 412 zcmZ9IF;BxV5JnkLD0E<{5D11-SO7uE!s0GL1td$9qN+?8EGKbl3&$7Pjw1d&b}Nuz zz5Bj*Pq#n%Ad}S-R)jp7uZ8du>tdn~XgV@tNJ#R$rs>%n+YX)bVkLM@mxRRKELpF~ zxa&);DkSGS$b#F?z9S?M`&Jk~BICT{*1IA>a`89w&Mn_q-pOQkScHqOb1S$Pz#-tF z`nh=*rZvzdG!|R%G6d{q3wO7`wFYcpkgAg4B=)+7XhzcqD_n=B29I#LMJN-{EjLEk zKsQb~9}HnoUIzR$*2q!bC@pAus#SUatH2aaZMh9(Ikw6(8Jv{aI2NUt=cN`58y2vU r=~yW=4q28Jdo&$i-6(X|v7R5l&~)aK literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/read-i.ri b/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/read-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..55299aa0666001bce36ad61d5c2ffeb9a5f6a5a1 GIT binary patch literal 372 zcmZ9IF;BxV5QQ0#X{p3iArK5EEFhth*%eYyOC=AbsDdejYbTe+!tq76)2jcTq!9y* zclY$YckguY#m4J7W{kbs!xBP?c{i&3}lFtPj z)r~SbLw3_smePGUHDfKZslbK-8zr@L!KVb-?O)A@baLxtU6ScAB|MsUbXqv9C|`N1 zEk&1uqm2#P(2W7R4dsTaLjX@pxdW;IEOn59-a$SgZ6bD_6xslfu8daC*>7&4apKfb z5GPpaAj;ND+pQO!p9oSJ5Lk!|ZD?bAp}^oij^p%%M|TgsH+`X2nZpYpFYAm;KA{=qhPuMtUFr056$&Z~y=R literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/rewind-i.ri b/.gems/doc/multipart-post-2.0.0/ri/CompositeReadIO/rewind-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e04cbc8dcc44f7460649cd2dea26a394b6f1b7a9 GIT binary patch literal 249 zcmZ9`F>k^!5QbrfDxhYKs!D8Ofu;3)T~bkyJkUxArVN(tIOSB^7uk+b|9y?13-hOY z?tPdYq1u0t26*?sJCjb-wG~czT?TVT-xW}7w!EIN$qf`SnZ1!6|61JEx8kscau}6G zO)$SoI~jh)0U)!ZGd|6rYz7%pY$x#8^k@yQpDn6a{f`Qym!OKQ0c*%%5~utI{dW|7 xASaSk)(Gl_CZDnxg))}TjInmY>*;cJIc>@uTHS?S2K{vH`lR5bU0WF=`vcQhP=Wve literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/MultipartPost/cdesc-MultipartPost.ri b/.gems/doc/multipart-post-2.0.0/ri/MultipartPost/cdesc-MultipartPost.ri new file mode 100644 index 0000000000000000000000000000000000000000..5b783100b50c95378a5338f6d92883e4fcb5729d GIT binary patch literal 459 zcmZvY!Arw16vlgyHru)h?jX2Z{{YSTlPtMew#MmNH0~9x3n82@(ug9=j)tXZzS~JGci$8t3pYShEVau&mDuU(!{+-2 z%iM{=s2umX#LD?>n-|L9H)R9LhLi_9+`{yT@radmqH_FN2U!xo&)09+%gRSDvSjwB z0l{gZqfY~@hD4%(gqZ}h zQ{9p!W8DKvb+)p&6WF+)6F>Vpr>pupPW?E5H=n1m;zS1*sD1s=v&Qn&e}nb2IwcH8<$f2Y$ZeeLt+En-FFR2O+WS0lw zz29f9Z~}L$iRJ)HUFA$I^rlgQjwFtQn?<9HELmk(rUU{sokd=#;o$&SuZ3R=k zO}Q?NrLNOVD7_C!Hzd7~b|^|FnpqP5lFPltBPLbQ;LhRk3@!f(9+Bvkd?cw+vwg)4A48XhPle(Z-cFq#D Ry&)UP=f~pKx}1xhP`^7VmP-Ht literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Multipartable/new-c.ri b/.gems/doc/multipart-post-2.0.0/ri/Multipartable/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..d7eb1a0de3b6026f0ddf28c1f51470bf7f1532e8 GIT binary patch literal 295 zcmY+9K}*9h7>0L{S?o;)L%fup6pHrz>7bQvP_Pq5dypPN(xx_;cD$^zeQ^`x1XjyZ)CpS2gQ%%N~uQvcT3!9{&IdFJM{# literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Post/Multipart/cdesc-Multipart.ri b/.gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Post/Multipart/cdesc-Multipart.ri new file mode 100644 index 0000000000000000000000000000000000000000..9710fed306c6cce49e5ef9eba2492201e32b4e8b GIT binary patch literal 486 zcma)3Jx{|h5bc1R^eY1(76zoSlg#HOQUQ^nRR!(jA#zfeS~zhOUx1&_IjB^E1z9@z z&hOrPcRmZZaP@p|D}a^lYH1cmIwvl4n8(qwH>g|LAp`dCn8!COg#b^R%^F~B9o@Qp%}p=+iRop_}1t$X%r?0#5QS3 zE2)oW?z)nAH;`tw)>s^r-09}k75mQC1!tRU8Hb^3_D3!4vDIceNl8O->CTOfqdz>$DSoHT^^N|6;w;xDQr%XAC!6Po1?c~gS^$UvBySO zgW<4mTB+?<#gefymes{nM0xQaBP@g54Xsup>@!$6Z!w6GhY`-4SDzeZ1a&c2rbljs zJfG4$F6eCR^UxEP?#~uhQNVZb`x^L^HH@gFvNR)k5MAj) ZSYW1u literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Put/Multipart/cdesc-Multipart.ri b/.gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Put/Multipart/cdesc-Multipart.ri new file mode 100644 index 0000000000000000000000000000000000000000..82f784b66b6c64850db6798dc6f95a4c96077db0 GIT binary patch literal 484 zcma)3J5R$f5bl5+_mzQ4EJzGtCz;Pnqyi#Cs|wo5L*%$FwQ%Anz5qWTJE&BM1z9@z ze0SgDd_i|`^?Yw7z}j}TFiRtx;|ooTBwqCfbt^g~Kpq~8x~qB5$qhf>-GJ&7wTW$Z`B#u=MreB=+|-r41k z@GubYP8!%akA3UEH1LQ=MKY0LV*!Ix9>KKjE2E`niXd(~i%O!}59zG!^t(V6k|LSw x#-V8BKp#fgG!)ouh;tvk*xhM;%V6l!ul&X1Y1?qBN7-5QV2|W+K9+xf^9%i7kFo#& literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Put/cdesc-Put.ri b/.gems/doc/multipart-post-2.0.0/ri/Net/HTTP/Put/cdesc-Put.ri new file mode 100644 index 0000000000000000000000000000000000000000..a5a693ebed00f32be1c35d07fe818f4c64e16329 GIT binary patch literal 399 zcmZXQF;BxV5QQ_K#58S}N-S()Cz;Pnq(VgoN(JrYA#z-o8l2d&FTl^oE|djXI_d80 z&+okpvV*JVJ0k$r#`Rn;HTRw^6ln^w88LE500 z-FtV159H?c(F#Jg*7sbmG!KDYE8LWm=l%W#5%jcf%EeX!A!CE0h>KnKAq60c_LkiJ z5p1~s92_B$ZRn)|Op2xB9s|^0G>c zG@!FF&tuLQI$SKQl7OG+^eyr!YZz8pZE21vW*ME-bXqgil=oV7m61@L0bJ#5fT|xf asO0v+cj;79;`p*yt;OyC|8DGY(DE00t8VrH literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Net/cdesc-Net.ri b/.gems/doc/multipart-post-2.0.0/ri/Net/cdesc-Net.ri new file mode 100644 index 0000000000000000000000000000000000000000..07d1a00eb31546c892bab816ddb5675af7aa69d2 GIT binary patch literal 337 zcmXv~yKciU4D?XgY93uObm-;|-D=I$VxSMeK$D?OCJlzHFpW@I5+pk9=hsdU5IEp) zJd(#7wuAf6SFZs!KK9D4{eG}0SB5nu+aTqTzrEK5_waCOTdVjp1c1>q^yrAeybdZ- zk{QhEgR#hg*Sia3F;= z;mP}a<;-8<%jKggF@9F2W^yK3+tLf+XYu4o3#m38e`UrZjGpFMeC_rv#wQR#fP^o_ z2QMum=w0F4J>`O#&rV|u{9Vl(>*Fxhj({RXJfHaR$9Jc9L4a)x(_7@=EPhyWZFmdQ zZDhAR;s;ZaGEpg2E1FGIsIIA)`I$O(9HeU@Irx{NxbNkrrs$C*Rkg7Bma_`R+I($P zom*B&o~w0Us>V8*yx>yp5)vdNOy~eUM4^sz7rl?Sw>}_2I)NMi2vLuESsawEOE*D% z>fum#g%l-_0p>S+=aBRUkg+z(LU+6ZEe{X15ns%5cgW(AXj;pfk{^l4&;exBuVYxj s-|E=-%w_nt7{39ZP!09PAUSjmhWkV)oq#!)#+jR!SAXAsp{h>uU%=y?IsgCw literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/EpiloguePart/new-c.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/EpiloguePart/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..1ed525c2e644a5f7b613f571ae522aa7009e9b80 GIT binary patch literal 246 zcmYk$KdZtp6ozpJsl^T=h|9&L({<6z$ED&`=%8GrP8~whrW#ChO8y{zdmCLG&wJp< zGmI}VJO5z?u+`6_a5t>WnH=S5ti>aOXkX;%;-4930rs6#c=aNj0O7xh4h1Bg=So%x zKOgAG%-weYz3N+`T?|Rq1)&_kIBTR5c{){+uixX!@SZ7vWY|haZ-UiQUoCA6w$w4M x1jU9{s9jH4%7wxQA*3AS>ExHA*EKWGWgxQT(8J%6p|6^Ms!nKHrgn;1OJ0$7PiO!D literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/build_head-i.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/build_head-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e0566fd2c500638159b2016bc5d078ab95963bdc GIT binary patch literal 311 zcmYk1K}*Ci6omI6b+L#Dix&@udQm9a^IL?98Yr?NqNg50(xz@O$ty{U6!E{CZWX-E z4DWrz>@DA5^>U95z^xrOGHkJ}S8Bh?j>MpJ%eIoY2_z4+%Fdp-3m$+fEhl;Y?_!-$ z3TZzGtr~>WnYiKZW9R`QelXI8C8T9PG3o^zlwHJB*|ApQdKX?fk*t$fC`vRc?246r z_pEbhSl~iSh8=6rhKTY^NR6LGQPhhnd%O@h*p|C7CzczTlLpA4R1R>6@&OR8_9YTfDTe|oaPlE?l5H`#apX9Z&u6y<#N*<} zu4i^<);r-7pUkgq&H1f$D`l>X>U(*l!y?_EY6JJmdB)kzv`CNX+;jdN77U~DUG)OB zXM#Oie!8WaDfc>boFnhBg4TyT&N~82WWXq=ICjje#avIJ=@VB*oo1Rp(Jo*CHJoU0rO-ox5t2$#T2WzI+DN=yutcge|?Q z43u_J*0%LjrmVo&bta-r#F=C=LU9J#rN@@oW0A7?hAi%e%IF%U|0^U%2t(&~QOwqn zt=f@@@-dR;6B)>$NTZruCN>$$K zy=rUtOL15Y+B6%Xn3@uk*e8rQz!kfD`Wn#{iGKH-KVT7UTN&z6_BkAEcWXgD#$HJa P^*XIjetwjhZ3Y7$``x5( literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/length-i.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/length-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9cb856be4740d62da6769d2f50bda5a5162c7907 GIT binary patch literal 231 zcmZ9`K?{N~90l+WF(iWuqKmh6FVBB3MkVY}MA*s0*lg-(I@ujd%Oof-qd@* z;(pROz`;3_Eu}}WuS8S23IRH&1P3=}oCQdv5<}en)(9m8qdSUF3Vz#hC36kI*SawC z>RNyv?rPCE5B#_tm}~;GxacKd=LE0+zV%F!Z@wR{+SE)P6|*+{03%XLB>(^b literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/new-c.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/FilePart/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c546b6982c76781fb078c3ca8bd0c15018e5c0fc GIT binary patch literal 262 zcmXxe!Ait15P;!5NG%o*!Xk*5kc$dMa~=^YY9WUek$UPOByH*j(@aTHmPLGb8y9cG z4D<0H0JidOT+2KoAfaN)W+&G0;Jo0RyR;gv$Cc` zxI7>m>A&U)U=in0yO={!P3gN`!AUhN0HeA6@=0jcZ{)i#p%_x!rArG?@Qw3s7qq7BuUUdkO%VpbCc+*s5w3T4^PeA P`Jwa`{V45|l_9WSX2w&p literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/build_part-i.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/build_part-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e83c968531e8c2129d6320612a4cd95d0160d1f0 GIT binary patch literal 280 zcmYk1O-sZu7=-sAaj~EXix)4UUQ`y%`CWvHTIgX#L{B}0q)pvmlDFhTS;YTt>VkNh zVHh4}_U5m!c)rID;MQ%|DsHfE7ka-bk7UxO=cDkE0C}jJl0Ic00I~=>`LlnO6{%|| z#w3mI5KecV#EG`XNlpGC`CN^oD+YUrh9> Y$WIRcF65~0PIhY_(OY5ej0l1K0K2JMHUIzs literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/cdesc-ParamPart.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/cdesc-ParamPart.ri new file mode 100644 index 0000000000000000000000000000000000000000..f9244191c5dde635df80677920aaa5f4af0b24fb GIT binary patch literal 485 zcmZvZu};G<5QaM-$8FjmgeU`B9sn|*mq>+58Cnp~$wTBMZfkJtC~+u{&$(>`1F~e< z_xrxP|9n9=Fn@itCBWLYwa^PKx{hBfn#IwJXhn^iBS4;(S$yNq9l&p#5e$dV#fK~% zVdUMy-3hi5?PuQrAi1xlaTLO|@!6bM7Eng{2qx)PX_>`WS``mR@xCoQ1(MX(%H?}0 zDrI(EzHM!tJ5gwv+ihN2;}F^9h1B+tuyMjB2_NAi9NQlIE|1Ne3$bw;;fsF?@qh?s>&Kp)hHR}clJ%v2rYQe Q-omoH{rj6MTlHH00M@FA?*IS* literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/length-i.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/length-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0a9ee885443c39e153f2ffc38431113a5bdfdf75 GIT binary patch literal 237 zcmX|*F>Avx5QQ@o#nccegf8jiEbWqNzAP?D3?3XxX(tata^zT4(iur6fdBhlhHure&6DX^){JKz2o$y?t{RJU|R?#=g9t*Q6*Q?FXS% zgRr=vD(?P=9w2fDBW*|^&HE8hPvALkm6m1pqLui(jw>g~n*0LI(Wt;W$q&jNJ!>5r w7P!!oVapn{A)-7JQsaqIT2IPs`u;J#=4n)%J>23{G_N<6JvzhnMsx4!1+lqHYybcN literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/new-c.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/ParamPart/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..585c21b691e6285ac05480d6036f5188e079e7e0 GIT binary patch literal 267 zcmX}mO-lnY5C-5LWL;b+2*rb5mYh_I<~$;-sD&IVQr6QRLb98+!F(+FuoUsXH?iR9 z9cGw^_oV!Q#pcEK08eJW7GZ0LZXr(zDvj6`P`tJTUA{9HJU|Mj^9+!W55=m5YKmOR z-on*USu^()CxApoElen(YNq_&&ETvVr4j_4E6MNwmUoUPrUl$sEd$*OHc0d7>FBJc zfpI0M9cgb(NR+2sD7(WLcQb-+uept8U~a#x4bx&-e=`+RWJEY$Kh{6LH(7706+!d= T^0{|^acui$oo4D;G4JsKLr_)T literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/Part/cdesc-Part.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/Part/cdesc-Part.ri new file mode 100644 index 0000000000000000000000000000000000000000..47bcc74d8708b90096cf72b250d0be79b3cab887 GIT binary patch literal 350 zcmZutO-sZu5bZ(I>~>ca4<5Yr2WZZdOF=F4up;W7atLXfYA{VonyNqFB(gUd7~Xum z$D29BN4S1@a1!9j`AL|A8&;#(mBwAYc@{n(K#y%#UnIN$w3A9KOb z@pQs{GVl`sUZb9NmSJ5GM@vjGE9i#MEn%puFOBZ+@@coePr}h(eoMry{O66oqfcjp literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/Parts/cdesc-Parts.ri b/.gems/doc/multipart-post-2.0.0/ri/Parts/cdesc-Parts.ri new file mode 100644 index 0000000000000000000000000000000000000000..724533fdcac7bc830513b61d29db173a34afc785 GIT binary patch literal 336 zcmXv~O-sZu6zoCL*meckg9mT@0owD+rQin?ToK(p>P-+uu>$TXlYMASWYr+4UWgMr!D+@>^_8c zB`&sR=9_OG-#p7#{N~{kww!-M-z#%xR0!f)=XEh%IfJUJ7a7k!FRNi)j2F#MXeleR zCGxkYw6Dtl+Bwc6$F2uUIUiR}c?u%Ka+sHS{Q0}b*zd}#jaP1)rEpy=?$GYRYOpP^ z9%zeQU~BZO17)<`u!E*8TWbS>DciAn!Dy?9DG!X0HNbYqR-wC1z41|%uyygq=;lL< zy~Cghq{ds{90BtRdrfi+s*ChNu08gWRAWHmTDE8@P7-7T1`qRcG%v?X#=s7*4aT#<`mIXQW!vH3lCdLIL+dIaVc4#yJF;#bZiMSY=5 zJbdE3-YbG+#B0ztkct95WxYNLCVL%1T;@OSnTO!ec9QVp#am7jTX_}Vfyh>uBZ~SH j{3gzS#PS-g$n{`;KA*vP|5-JwX6^Oql9uScz#hzB%_Ge7 literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/UploadIO/content_type-i.ri b/.gems/doc/multipart-post-2.0.0/ri/UploadIO/content_type-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fda546dc224b2db64bb4577693dd567ca76a0b60 GIT binary patch literal 1027 zcmZXT%Wu;_5XL#6^u?oG5CRS(b7`fJN2H16Zz|XvmHk-GFOwXDWO%P2Ws$b9!IaQ8tX8R zFWzlz9u0VJa5>n#`#;Yr!-0i?&gU)!T~Yw$(D_t8Fw!4C8 zkEv=N025%7EK); z@}$VLeb}g$;>5VkQhvJ^Ih0fC$yBmHnyB5WY{k(lYtk{t*|=axBt|~%N+(lS8A{6a sw1h;mOuC;UaYfP(Tu4%F-E#7M8pYAmJ0dxsytN3%MH_ zjgsK{$k_=0H8_9-9gMPZ26^d(kD;ExdD)>>RdJ=UxtC-d1&oR#-T5Xfgc5aocZIlZIc< zjO`Y+oU&QJdGF1e*{8eL>gCl}mn!v{$ln~8-8kAYZlDI=7IAcNU0a7)eEE*Ajt6`* zxRPHrteeD|)TuXJ@j3c+Q!B+xO{pu|Rl`}0p2E!wr`|rq%+ce@V_gi6_ilFL==8*E zBn?9SY2T$ z#xqD=Mcg;gw$`KernB_P)w&9;X~DPcaJy|YhvXp9kXjdX2FaEgE41d1_D8MV*+K7W zFOKHoAZV7!{#mF1t&nZsiweg!f}~-KHaPJ5S7W>uqf{8rResfuX4HpuDM8-%kb76c zrZ8y%hG2sMgpzF?N_r-3EPA_zCg{Ae6VFCUo^!?kllO!_y6MT7GFDEB@hvS!#VN|{ z_{4+L8|T-fUd`p48wC8#dH05ZbLrCi$fH1?81m>1(@ESJTw%JtA8gx#a8IbLALTZP zqv3VHl~zK>aXwzxpV}u#rrhZ^adfxt<4SK1BME0rw-k*aB7IAf+M=nVBi5_gNH2&+i;befp|&Pb`Ko{R>WYM@Ikv literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/UploadIO/local_path-i.ri b/.gems/doc/multipart-post-2.0.0/ri/UploadIO/local_path-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..276e17880dd883669ffbb10679525d9b866781d8 GIT binary patch literal 1023 zcmZWoO>fgc5aocPM(jEY54Wb z*lD5VlDhF!tbsk5rt{dwxk1yZ; zb96l5lfl)1ziO{(Q)@D(UiW0@=$CDy6f?J#u4!BCO&jzSZeBR`<{@T=9v2>)a&WwJ zvlU0DCtf3Iz#7_47UD|?tszXUhQfI;b!OY#)C*n#l^U2Ds{kd25?lcYVk(Z{LX%Rb z^Z87vnG3u=Z!H-yG7`jpRz6#-muIHdPu%hD#?ILZ8zEe3pp_H(DvV&xqJ{B+0JBUt z6j-w`R@YdG@f;=xM1^A;LfW!L8ytB3vo&6eQ7Vn+TYk~CX1EFK zQi8m%q42JPRcW#k48aNm2qoJ(l=Mv2TJ&}eZO}z)$DWN;+~=GDrq~dE@4F{$%2_!h z#&@(F6{je@;}thfubf{FH)^in+#ujD&U<4BIF~-X58Mj$sUeTvFrCDm!xd)B`^I)9 z2=|z(=232gING}oxX?=IIL^o8`a}B^$y8hYBo6P!epKt#VI<*<=$4`(M5J$N+*mYq zbi|V))As%WTEK~M525^bPjV!;)U&B%fizLOQ#ssFI*(*RXhhCJXR5ey?2KQr|7`P&TLG_fP?uaoki;y)0#OxsIN6FW;{Iy&tNNCDd^; z9xcJe9=X!#bBX|kKLt1DIn-^`DRVc2qjo^=WOMG(+*=Bf7_(DIcga+R2BM{aS#6!} z%RZ|iQBYYM?-UKn(wGa8m2sZFgb>|KHpkbuI&Ju7*Kg~hd-A8dOYGU+>XlN^{>f`* F@dMSRQ*HnN literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/UploadIO/new-c.ri b/.gems/doc/multipart-post-2.0.0/ri/UploadIO/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..835e9fc8dcda61a19e7cb66386ca5f7f509029d8 GIT binary patch literal 285 zcmXw!%}c~E6vX!+wOG8!B7&EYlS0v)pC}bSAcs|u?x}~6wy7IT@lh`QPYxf<+ z5YUPwTcZRHqC=M^Vic`1xMhqr3r?SIW~P&Ns)PwulK+}WJFiM|Ovxj0+LQ!+ij)5R cyPZE)#XG0x$62$}T^@FPV6f7>7#Snm0|M4u^#A|> literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/UploadIO/opts-i.ri b/.gems/doc/multipart-post-2.0.0/ri/UploadIO/opts-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ddff43d4c2b0847d4ab866f543fb83ef4c7e3441 GIT binary patch literal 1011 zcmZXT%Wu;_5XLzm_r;^)fRNxYGM82gNe+m^wue9g)lwg!O1bn9jqP>3%Gzso$E4w} zXU0y8T29%l$KUtOZ^lozuhq+|uP#&SGm*d9H`__P;~EN)ioVT~_|=Rts6b)Zu&^auF-YqLQ8$u4!7Gib3hJK4ViU8=a8;hu|{kDXn)wn zo$PN??IiJ35(LdQ`M(G?pcS$82XSF+14vtrXoCZqT?)wi z9t!U&Sd}I#!4Rx4fJkzz1EFWK)}ps-XoD_VJMtW);yLGBV2X|4kA8YGrktHK;`&aO zQ87iC9iMn`dgc6buyJz*bAy1tnfE3TFqfX*Cmsd*)R0GSSWa-~aE00Oez08&qCKLj zdBiPB;=SvD3#~+saXwzxpW3HLrrPQ^ad5Zr!&fgc6y$*1mh#b4g#;2$=F&$>a#Za{Id&3B0vc#Lbx1D2w~8>+5=!epnOwJpGD|)IRT7vQYY!Fr3Tz1o!Bi5% zxg;S@7K^zMbL;th)@oA0$T%P#S^28btWK4YPwdgN!OrP18zEdtptTM1wI9QRMN8#8 z0p_`E$g}2cbZoqU+#2G!fi{gCb-(nMKHEkb-W*`oFqoc!G?CxcO{l;c}&*;O+d z!nz1S-px=tTf@3ic?F7KjUECe+d2s8sl3(b^affl%T`Yu8>zYHf&r==2!HnNg_;Uh z&WZ6IEl0&EhVJ;p#mTjGtI?olOU?~E{^7g_L%_N8>3!lV&}E7oI>mHhQwzAne05iB zH$vc^P~AMpElT3uE00Sl0v*Tsa9w{%mm#TotKY=Y?e>q2Tpz?CoH5-{Jc5|y4NV%2 z%EX7fDPh|_-a`j)s_cCzzul1>hFjwKEM$Q+70+hjuOxo0RW{)`8|xJXim}T&=yYal wMQPPnPmM_xsQ8Jm~3TjowfH0T1m{p8x;= literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/UploadIO/respond_to%3f-i.ri b/.gems/doc/multipart-post-2.0.0/ri/UploadIO/respond_to%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9f3d27c2a73ba392c2bf4033885f39fe9db1e9ff GIT binary patch literal 270 zcmYk$O-lnY6oug~WGoJXiz14fVcaN)W_?8*Q43jALE6{z zh0iR8L|zoB&cG>*m!iP$_egT!pFcV<_wd3*fV SzgzU_zVwZfm-vh_XZ8yx9ar@L literal 0 HcmV?d00001 diff --git a/.gems/doc/multipart-post-2.0.0/ri/cache.ri b/.gems/doc/multipart-post-2.0.0/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..48dd3d54aa9b52a687809372d1b20650b95692b1 GIT binary patch literal 1673 zcmah~O>Y`85Y3??e1wmNKr8i&`qEQS)KldiO4WesLmCuqPC2a1t_zNK?Un5%s`&FA zA-i-a;JP$AGn;z~^5io6}(wiBeUHC&r|4>f{Xw~I#> znA+ExM^O7diR3m7pGVowFJ>_Q>3MTN&yLdleH!C=YC9fd-WM?#-=vY@2~`e$O3?W} zLKhLUO$aLK42%w2NnL*4hi9Op11E#>P6Q3+a4QW|sG_m`y(I)UEGX8?QCk3X%OW!# zv5K$YE~{eI84gKXctC>u;NQDpzJr$6g18bDy%xfVIAZYY$^7{MfOpY`;4HM#~wS~`KtTeOMN$5KjzwU zb^RN;sfM!LNIk`LB1PyM`OOuT4->}UU8Fn;!N2Z_!UNqK40x6fIImjer1w=GZp4%e zf;xB8@7FieacrgV@L4Rw6h`-OQLgjh@|tHG$?lgrEFs6CxIrgx3Hr~1nhXj0_s%4! zx!ol0fGV?=>rk=e?0PCp9XAuY1l}jOX}F0PL7(E?-oAu?6?6G{d^NrrUCSVi!Bf<5 IDXe6F0Zozfb^rhX literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/BasicObject/cdesc-BasicObject.ri b/.gems/doc/naught-1.0.0/ri/Naught/BasicObject/cdesc-BasicObject.ri new file mode 100644 index 0000000000000000000000000000000000000000..a1c816589cc0f89d04bf984c75e26dc7de4ce909 GIT binary patch literal 411 zcmY+B!Arw16vlgyG_Kna1Qk38{R3RjFPGwU(8DIEJLM3PEZd@KQ<7Bu^OtrGCV>Z! zFZq4%d%3`CxOscF5@2Or&CT3!@9DM1Retrvy_T=yQ^|k;y)3HyZpFLZJ^-9c1V!cF zWr98|+#j(^?!LMfAbNDQY66C=Y`F`bB1=+CFil`oZnaTW{$RA2HG{=W^ybVC?vGBO z$b_P_wGM2r_(nH7&$iCiEO22Ivs)%@6QY4IqWFM|4QA|_F z+D;fPqn^UFbvDGDYBRLs*6D8^RNqwjL^nS0Myk_OlJx=^4|Ni2LecsZc;1ik8+Y^` hdD=D<>!dhE{Tm9E(<;x7%Z$*4ygmPerQLK!9RLO5dKCZw literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/Conversions/Actual-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/Conversions/Actual-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f9d538a9f8c001127591e7045bb624ac439ee87b GIT binary patch literal 274 zcmYk%&r8EF6bJAgBo2ESIPf6oh!?%Mp5G8U)Itv3LFTE4kfiAvP4h~ADE{|$PSER@ z_xrygZ=-*toA+#~#~eVNMy%H!3D!36STC(d(^9`#u6ZqWjQ37THar?kKj{}cFTFtTJQz1@n;8I)sEDA=mL#xRcJ-LAb9yo|{)I}Gs^E-r!T8PjaM5hiRNz-dI%`5q#+<$NGZqW7n z_k`~#n)n>FfzeVw>WLP{btTuPMxXRNDXaAve6 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/Conversions/Maybe-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/Conversions/Maybe-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2fa3ff863c2eb6f9fd2aa2bdcd1317c6ba1ba3de GIT binary patch literal 272 zcmYk%y-UPE5C!lQvL2U4@W4WlBR1N2spk+PY9K|f5Uo-yyUFCTy4eZ)q1=D(-lfp? zG4IElv&9Fj-d?B$cru3?{Xku_Qs-5+ti?eh1NK^0+09Ob{onzf$$X=Aij2FR54Nl< zA)SKMswKFdty`n1Z=nrI9G@>*8;b;ILs2msG$zm)SDtzRAf8&Z~# zO;H#v5w4C>&E03501_KVWy2h@V&X3Nb_VA~uZ^nm8>7YA9@w?~Qy-il8?psj;HU!| z6z{a%dDc4|S>VDbhCNGxkX+A%GWbm?ZD&<}dxzpf$*_D}g2gbT9GkfJs=NOsi!2Sf V_%|ROOL=*0+@Kq|sj-Vj(LFNyTKxb3 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/Conversions/cdesc-Conversions.ri b/.gems/doc/naught-1.0.0/ri/Naught/Conversions/cdesc-Conversions.ri new file mode 100644 index 0000000000000000000000000000000000000000..ca18a00fe9ebab2f7a5713291414815bb9f7c49a GIT binary patch literal 506 zcmaKpy-ve06ooq=Crw&}!~h71ArC+^+e;8oDM;x6bn*~6j@w!|cI2M|Z;zc4%7Bn3 z`}lt6-g8glHN1F!P!z(I(j5_%YMo&CoX2H$cCX}~X~UH?0D{M5nO&}k+wLrcza<2g zxq{aROhxpY>ml?^*D+~hm=-x4Hocyu!Rt z9k=z4k(SG?sW)16wIz*Uwc6CazPtMrmHL1vF6RJje<;2f#Gz)Yz9|i*JF<&3NWgmV6FTNeW865LTJ|_De0x0I* M{IIG(r+=*Y3#mGkI{*Lx literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/Conversions/included-c.ri b/.gems/doc/naught-1.0.0/ri/Naught/Conversions/included-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..4b8b8ee678e647b4889ad4d6eb6800f456d73725 GIT binary patch literal 271 zcmYk$J4?hs6b0ZdBrXO)VZlPMm`WRW>bp%u4W!5x5~~!$ys{a*nH%Pz`0tG_sO{mL zk8`qqh0V(oX@Cd++1fOc={N4QVdu_k%*L7mis!mvY%lX+OaPDM-))GFd<6I{?TWgC za?T2!Cb&M5tqgB@23Y(&S)bNWRp@a7U_d?-me;VdFwNx&?sZP`$np=YuLrV-%D8QtK-K# Lg-K#dCZpwF0QXtz literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/builder-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/builder-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..870697cc7d904249ae99a3dbcbb25db8165a164d GIT binary patch literal 297 zcmajaF;BxV5CvccWJRWAaM z^|dP8I>@WgwBDM?&sq$|on}4;Z+R3FHTNS|-o?!1v_}8cbnTMS=YOZ<;!dr~$Gs0$ Hl*P?AA!}pf literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/call-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2f75c0f4251f40c3892d766ac392ac14c5610845 GIT binary patch literal 276 zcmXZXF;BxV5Cz~4$Ss7iVqpsl2thnwmp~y>hGsx8Ww30=X)Mlm(zLYT-( zB{TBu1=*2LptUnPuu1Vj+vCDU?+goEpki)h(%F!hlve0|D5d?XE!X!Cr)XWIHrM|@ Qr$Hlc@{^tOhUaSZ4|+XXZU6uP literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/cdesc-Command.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Command/cdesc-Command.ri new file mode 100644 index 0000000000000000000000000000000000000000..c3a09672079f1acc93c2c0ed41878da64e9dd23b GIT binary patch literal 566 zcmb7?J5R$f6ooq=$4wtgB^Jbzfeo73ULp#WGEk&KCl8V1xUIplBgdiqe6AZJAt452 z$&#Px!0`JJ>_Q485HrCZ#uQYF4woo`vrYl?5+*F95$910EY*vM0eWeXOO zdE=~y0m&*Pk!j=92lp~O@?@q=>$wr~hsD`=EV$MXTn7)}RB|uf@TSv{O=obA7}^a} iUxn^JVPh|VQ`Ru7M(Hr`VHVjuPpk0&@UqLOAPUp={Dx4S7J66@qNg50lBR1|l2_6M5%GUtX1qS$ z`+o1cn190Z{S`UDv-#c&H(=K;tC(Z!Lh(_8_Le5z4bt zi;TQ_o`?=`OYP1W<9Dk#JwdmZ Q>Fa87pSQNo8ed46cqcU9e-BbH;R@8B+*pCy-c3&1s4O8Kd=t(HH*@BJnh!q&Ei$jTb}NYUff{G) z1zhEwki1G>q-at-0i-(Q6E*^nW+q7486a(^e8SHFg#8gbm?qjrZ;<7vgd;tttXnEWxqTBc@qEt literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineExplicitConversions/cdesc-DefineExplicitConversions.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineExplicitConversions/cdesc-DefineExplicitConversions.ri new file mode 100644 index 0000000000000000000000000000000000000000..b7c3af4276153f694247a13ca35ec637c5fcbdf2 GIT binary patch literal 686 zcmb_a&r8EF7~MhAZqp$MdJsHR(3|Z!xs?47D(FGoDTk7#nFiCOBHare=ycM=xYtBsX)hl3Fabt&&{&nbB)uoiy4Zj24eY zGJRp)$EOEqr*^<;Csi#h#xv72OxF(MzexxJj=Q5Ah@f|auXiG!nf>ZoU^TpJg!VBW z=Pk3|QDjIIlb8isVVjD%HKjRD;5j2XAGy)0pzT#I){hmSXR-h^)E}-~S<{rBRZ5g*6#yQz0JTtNlaXOYMj0LSC!$f2jQY-jiN-X-0{ zq)?CWq_xHi?nT`{Pg^V3%!}|Sk~68DXPS!xl#D3~g&}83!6yvx|6J0DoQA&S3~odr z0q2j#ZkVlu(IDY4VlvDpU@^a?XnEKS#KVg%gy9X`KuBmT2iXsx9|_7QMRI?1<1RSk MSHENVZ0b&lZ~3O(tpET3 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/call-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b6237efd2437537759d02fa973dad20f6f53d735 GIT binary patch literal 351 zcmZ{gy-&k16vR8Aw2-x8L1G9CEF|;m5=aROQZpc!GFXn|G#0jB!Tdo1J!1SwcMeHk=V|mdpb+Uw#Z)WL|OYHW23{HO@9G zxXODWd6m3L(WZI^NOj03Yyu$dLXff(K-$guM4SK!I}<#bHrhoWkmaa^BLk%94@fe*F7NPE5O$ zEJYyDiF@vS@9r$xf{W*sq5y1^ZirY4VhlRxQITA)Sj{CXnpSYi?NZ5irVUrp1R!{L zERw~Bbi2KEshv0^E;=qMrU6*0rXjL20Q?Psfn(gBWCSpHRp9C%a!vGG*E*`AUBje} zK%BQkTY~}x!w5!b1SWaS1uK##!OK+k5>x3EV(Pu&@}M!LM~P|G+r<3n6Vo4~_qz1u zL6)nATfAqa;&NwjtyP09DFwr-_6gQ$acCygM+V0koMdR!pAdybGU+RO5{gg=;mPpEmR2X|ek&G!3!UbIe|Ieid$5vsYzdSm> z83M-YApoad8JxL$go5ob7PlLgeY#C}aaP=hpoovMVIaqT1o^y3?oN)|_)_%p_fD== H)d}_uzc1aR literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/to_ary-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/DefineImplicitConversions/to_ary-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b79ba1c5225b56f73360f1ff286d08125917ba58 GIT binary patch literal 355 zcmZ|LJx{|h5C-55D6Pm^u^=&o1s0O|x&%@p8L1r*Oc^Z4aT*KT7x@F!e~;5dVq$;a zyXWp|^9kGcJ#v6&b3O<^VApKrnq;X*%IrCT<|sD4z(loeeo(2zhrAP`MB&|1&(by-Ld96uCjx3x94{!`hRf;+H5~S*c1*lMK zW;zG37rius=ut^7eTC*rSSQiA`(@THscT5b(8d75?Y#HE>}MEb8+p*e_zk4x$gFqG z3a-muDnYV0CEMIw2)T&@$|nMCXG6{xLf%~jR4xR{{|ryIO?JsU6eViu=^$7q&Dqi3 xqNbj;N>J>lf{%tcS}6Q3ilSMOZ2j;!Rm(I!;_lxgW2ELc^G!#zn$3SIegVhcdjJ3c literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Impersonate/cdesc-Impersonate.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Impersonate/cdesc-Impersonate.ri new file mode 100644 index 0000000000000000000000000000000000000000..d8dcb4975a791e8988b3347de3a33348924057d8 GIT binary patch literal 596 zcmbu7J5R$f6ooS&$Mhv6BpBGTur(Q&ZkC7wQigT_I(dj3$89bAh#Z^p^KsHvbOQ-l zvSi)I`Odw*z-zd9eKHJSWvrrdA!*lY8=0cc6>hi?G_omX5t4CA7u)^!A#JjOXD z5sZqBki1MliaON;T&e?G#d;rAeV|L(5iS)!mgcq&a_^88MhRE#IBkU9cGbojRXJKq zUYSkBjCMggwBpk2v-~p4M;VER6O*`1MuSq{iC_}Lxb?LZjG#V-HQ)D<|L}#Lv(_5N znd426jbYMS@fmi~Kgwh(bmypM{DhE?`#?S!?rFFqg4U;*E_yp(VS#UzW5oM=o Z9?hX*Rwnnq?<@$uu-o&`vowvD{2SH`zS{r* literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Impersonate/new-c.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Impersonate/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..0666314bb8e3f7c755d7010be455ecc4a6470d3b GIT binary patch literal 349 zcmYk&KTE?v7zXeT5`$eFii=Cgq)<$7^A#al6*4q~#3{pZxm=pVyL-d^p@{h1y)*^; z0iNf_^PI(>u=;pK2Jo!Ex7-cbH7jvmrm^Px2%@*TOdl%hcY_0{yp$VBt$p!AcH97L zP${ZA3s9<&8;hDc4lrdOqxTw?qi>~P2-h>RrRK|z073MMYZt?^7^!i#S-?fn3(3nA zq-ZmJATu3A!X}cmvzf6YnTdb#&a}a+Aumt~M+Qzip?8+_1{HC%m7HKt7-|>HP{k$g z^E_`BWqN;eEM6zG z18Ag@{C-KDld6Jr3JfJTaJTk1)P9EvAYwrY?RSut6SdxT8`zhFL{Voalq}Z^mg{H{ zK4XNfTF(EmT+P;#Wyv}DgrYP`dNK;yOMP`@utpJ2846+s!j1M(izNchPf--zrp~qx Zk8`w4<8%9Ecswh9T$i@SD!Tqz`~i$cUorpy literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/cdesc-Mimic.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/cdesc-Mimic.ri new file mode 100644 index 0000000000000000000000000000000000000000..953c770475ae4a345bdcadf65807e864ecad6a78 GIT binary patch literal 694 zcmbV~y>Htv5XC(dlw!vo?4lXEX=pcFLnm?(>NJ1`XGoig13^)AOqApa{Alv$hm>rf z=whJIq~qgzKi=Jk@)>`6x(9*rBRIqLUUTp1MwM+fKPaOF!sy3CTWueCd^v?Ai+U1$ zk4pE_VY~-pxa~d0(*=T({>xQ8N;<%wr|<)JzvF;$B8f)YP~t^1a2Gs9K#G!-bcW~6 zQEAy$-?Zv>cEs7)M8ia8X5GZI6K9;A$@p8>rJ!H9ZosI(PLlV^zIb+YU|8UtmJE(e zfDI`%nMe(VlR_X?O@MBD30RNq~GFXu0WlI-MgxmyFq7Cf<`az48EC zw3fR*0PHS-mw)*+X=zFJWK9mR7?UtsB0Ohx$NhI20j3JcDi;e_G$Z#h9B<&R8MINf zd^K8BZq_R|;VkbLnXlxZUd?S+Ud&M4pw*F`74Nk>1vYrJEOKEK!+}Y3anb@4%HU7k XHutn#U47sLwDKt*(4n_H|D*l|=8AG7 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/include_super-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/include_super-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a8b13620952c00a14daf6073f663bb2321f66c1e GIT binary patch literal 332 zcma*jJ5R$f6a`=gWJMGS#K6L4_9g?>JEGBy zz8I9XJL9!0HdiN{%UQ40A70y&y$tdUHLbUp_)&`i-68TZc*~QJMsq)Mn+a literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/methods_to_stub-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/methods_to_stub-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..79ecd4ea7e83b719860e6f82e48ed9b9c743c46e GIT binary patch literal 312 zcmZ9{y-&k15C!lK$gNt&h=naIu#gN)R|y3QkuoF$f+>ULI8I|>`yzjU`0sHNCdN11 z{ocFSeL(W|f*jz<{M5pa*tdz?R%xP_;HXFHeCP;}*Ro0<8y3!^2WWy)C&iq54pQ~P z0-R85W_kxuOD*}${|84>mT);)`Nh0IxL(2aB3|)+s@8pd5{lT6`iD he&>1KZmM*9dpDmJhd6YZ(X)^!- literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/new-c.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..81dab22d9d2b5e96aa8bb80f9a34368fac533668 GIT binary patch literal 325 zcmXZYu}j1-6vy!!q?YS?xVV%~3dgme(-Wb3Ds*TEsZ)oLrs*}9omi~cFO9k6S5;<`ve&CdY@?{$$pRMedY3s5;JkCIN)s}r*02H=QF zQQb`drBK3G=BuaRqlRd7trQI5cFmX6e7h0ATTXFpLx}Q`8ap)`*yg>Eyht9UXj8pl zsrD9OGe+7~OW6fW)odM1>!lj99F?$S;ItF^G?Ct*B9^w26YL2?ZN26rT;e&)vSw2x t`@2hWAFqN%vNZQGj#i+a;^+AH?|$y*k^jJUSvL=3H|v}VjiT!_vVWvhZ1VsB literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/root_class_of-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Mimic/root_class_of-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..454e533a31bf4218d523d26cc50e437531681018 GIT binary patch literal 313 zcmY+B%uMQ&eLa(Lfp>p*60kIv&lch0%?W- literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/call-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2044c5fd5741e576595da9785c532a2d9945b9b5 GIT binary patch literal 292 zcmXZXF;BxV5Cz~4$Sq{8SlGe>3(3$f*CkMhl%WwqFlDf8$7w9icI4PX{CnJ(@rHNb zdsmw;*nYfP0q|^oPtuRJ@3v~)tLat2HzI z4Dc>FM|r=*4y3Ljn*v8AEZimF#N2n70HPMOG=2kFH8JPsZUr~hpinmX9u+Ulq7^1$ zR9rO56IY0Tt(X?<$#HTZpHNm-D^EwsdS%Wt9h}wFvsj1PfeLGUK17{+%nl&#wmW1@-PdeEEg#S2^-r%QU+V$_{DG?cQ9NTC7h{PTrwO}s5J zoOr*U-}Ax++@S0C7tIh_YtvAA zFOnxIs#Ntnsq#1_3)E$G1WMV7CvAHJkERMrD9d#tT)F487HVh9tCsJB?^ZOOE9 zUe-_HQXeur&hR87qy9uBDw0Vr5+)HyA{4h>B?TiOyGoh@bit#}m$E0T(Gb*JIF7w+^cj*^qc^QJ-3}HMCL-4G30ye|G7s2n3 lf6ouEDzqX{jIv?VC-)$q7sEo$OvJcr;&I2s?hm?9J&tE%c( rO_AT7GaqscehNN+&2OC_;&4A_*4efxvZd2phhHxxTC|!jKdAlzsby(T literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/parse_caller-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Pebble/parse_caller-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7075c2b74fae5ebb2fe0568837787fc11f458a3e GIT binary patch literal 308 zcmY+RYS{-2X`DO*ci}~HlFxtM`sAW^EC+57Qf+0$mLH1rZ#dFKzaSQ-$MBE|s{xvG> zr32Vmt(oaPz=z}<<=wydHmhsMr^rzW3%4`4XYM;r07;Kpny`YrN~z$x1zcByLfI5g zsCa44YH1Qm#Yv@nW=nBV%jt|hI-YH_FCdlGD$r4~UYVn(gR`0jmTFNuP+?6-T>2u> h{t!aCMN=&AA5PIKPc!p*Lb_{lGk0yR(`=qh{s1(5X7~UA literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/call-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ed1ec285ba2d260683cfa841457d63995bb3de65 GIT binary patch literal 323 zcmZ9|y-&k15C!lKC@o}dS=hn?3(0(ykf9JMLnBntDTC!WPGfPlBYz0--{U3~1M}&< zpWa=qj<7zw84mEGfA+!;rfb%6S!LIpAtsQ#msR#$vv3+bKphZw$eeo(5<6i5c19_t zI|uM#MJGA)!X1PUR^Lwr+oUWZ9Yc$f8@QXPJ+oh71c+`>Li-h@WMtO6W&t;(mnf=? zplowJxw(!k0 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/cdesc-PredicatesReturn.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/PredicatesReturn/cdesc-PredicatesReturn.ri new file mode 100644 index 0000000000000000000000000000000000000000..acbfa61ea542fdb024dbc144b37c5e84e114ab43 GIT binary patch literal 692 zcmbu7yHCR~5XL*8Bz-OjkcwC`z(%v;ED?oD8Cs!2Cl8k6Tw4prj%DpZIPB#e^wd z1KdM{WXlDlVIp`olMUHSIxxcOPDs|G%~(e^D^E=k-E{S+GgtHjMTsi7C3~PbmpenY zS{207OaM_^!j!a*z$FBs4pH2X;z5La&F5o34F^rVIuj1CkA`KH3C^%r#{vn5I`V%? zmw8fZWr119U2z|cO3lCAj_OAmj=40JN(M)ec-SKJ85P3)TqINM$D>*uk8wjj&0)(W zkOJ&p<)q-oxB(osX?WMgPm}AErjzurw>fTXUXSV9-Nw5k^zj85&RpQwGbiFO9(;kv~BE`??8YK&*u|r`5P>^kA?x<>+cQv-tcBAj;r*NV<$8cHO`0<&I!FsAbBdQ^tq;C*L#3ENV%5O zxrZPmM+>kvN>R-nz>7sL81?A3=!4bQ|0k}JvV_yYiqE)e;A+xrsQm~7K%@nQ+RtH8 z4Agqp%;2Qxgv2T>q-ZleN-`ZGgdHTLohTXmkz~U!gxFDXXWL|zyh2_WB|Pbo^4QIh z&KgBLZ6y-Z5oWZHKgU3n<}1(hW>%$VH!igA$o%agp;*LYoc}EvUrKf{^{9*chd#<__TLXW8x02dh{AhOU#cgww%__jt;{tE2?LzyC%-S6o%n0BnGo>-RMHHvLH>?N04Y$$f7|?TxBs#CMV6{{Dk?jc=t}4;=&tv zAHMG*{)FZJRWpER^|M1a=&o7v%QB4>9wUg}>N0(*s6Px2pz=a&1-16YbJ3vz*lH=M z>MX#A!HzTP(C*QBqX4GBWAt7_GWu3u59o(n9~ zLhv?ICpS}pC2Vp@JHr_}yV>~15_57lrVVNhd7&kDWI)<+b+Dv2S`tTFfkgL&Y2|_( tf++Mc&+}$crnmR!{KMVcBHvVaTu;3s2}i8{kDT_g>v>hBjimEE`7Z@}b<6+& literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/call-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..84e461e16a204de09bcb47d52ca084e30edb5223 GIT binary patch literal 301 zcmX}nJx{|h5C-55C@n-{s#w^<0t?9ox-Nl2qzui#$CSZx9H+53`yzh`@$YdP%6g~w zo_o($pRj&=Ap!7YesmeOx&JrmXpitXt(omS2nv33uj5~`VXG--RWYVh16y6YS s+uvZ(F5nB!yasz|G(~cdoMIl=5u~#$x;uMY*N)=Xzkjf$DH|oe0iqJbLI3~& literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/get-c.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Singleton/get-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..4d8aa1c46676d8d8d2ff72fb58948f3f05ed0b78 GIT binary patch literal 301 zcmX}nJ5R(g5Cq^WP>6^`b)un51r)>`XlVimC#AR)a8xNQ+i?;L+Z*{I#J|TOK)ss% zW=`^V*uFla0C==t2N@>pyRABH%6ya|gY0GBly@zQ;}ihesP#@W@1LU5y>tLOG=|yU z1H36aY8lW1EXjv#e}rO=Tq}Waxe^EFKH?0JylA8iITZEGT=3ln&gwyF*_8KM@yh;y zl}#QM3rP7YR^k_|{GWI0c+!qQYBVa)NwPkjJRKYw8W`7-;y?x3ki_&zYWyUGbepvC a>gIaM)aBkUIAkBzD3A?2J-W zcMjlSDHoKXxIZViNmW5Q28NOwxSNeVwO?Tbh+t4c`xT_+NUeA60&dD)qNuYMlq}b0 zFxSx|d;$rZ#hhQj-2Zt`mL=Qd07Yq(^kfjUlltUHZ;c{;YD7#=xY0g}@sU9DT@*#T dsI%q6;}k8^ICA|zAf76IJ2!5ORdn85`~rg=WBLF9 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Traceable/cdesc-Traceable.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/Commands/Traceable/cdesc-Traceable.ri new file mode 100644 index 0000000000000000000000000000000000000000..7756ee625b877c22e6efa3768db0ffc993c58862 GIT binary patch literal 595 zcmbV~Jx{|h5QaM-C;eQIK!Pm;Y$Rer=Ov<0DMLFzJ9&s4$89YfJ8~S#&&N)PV5@{Y z+4tVP&)xYV+`-k`i)H{DZ7M34k~R&w6k!%EwuUlJ3&|0n*HsohZfJWrS|@E~FMMu= zEV%(#>Z+ouYyf_fFmgF}XLFF#X}Ikn*3^8oHGm^(E3Rw^)3m0>HUw!Lgg7K4n526l zc@{lMQN*f4ij^bEnP<<7o+)NONUJ;@-f<0kPM+wk|SKt#E#jIFaV5R(8Bl_l44-iyLtf^MJJUY>4TC@ zW=>#cMvw9dq|Gd5{1?pppLb`QQL7*?P)kpH!CGk!j&>F`_0uAX9pz~JD2_!!;W5wi ndO_058yvhuukYKbrbxCVUH+e$e(5*7>9Ehwn^GBD0GZ=EHjktwB)eCkS}7{0v@!CZ9VxQWcf`Zst==&E`R=B zyXn?JHVnle5PJ3Kk^GaMWY^@`w@+3Oa%G+7>e4n*L3JXtGCy8gt+{D@LXyv`GJk!= z<7OMMG%B@J-20DFss7B4e$-$>Mkci7F8FF{i!>{;DzW7J z@7k~2@r~o{HtB}T{FUZ6F!RyDENrEp>0WRKJL!W@isT0w)3sDk<`+uVbJHu%4H`1h zDYE*`@vW=->IJo02DSy>NVD;5?W|^j*9w?jGht0YQJe+J{#@)WN5#0zzx)?J7yGlC zH?Wol80=al1+Ik1TX0@lHgT52f{Bi;{0v{2)( zILx3!84emLa5tVg2+^6txDNwy9&@4~*hgZ5;{v*z{jn*=3(P__>c6x~%Y58twhL;N zRVkUYvBnhPcuJ!*^oW7(vy`XQ({Kdas09jX!4u literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/apply_operations-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/apply_operations-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cd2ba11ad564a62ce3d25945dc69c439a960bc4c GIT binary patch literal 320 zcmZXPJ5R$f6h=FsP|=Pp3kxzr0tvO5ZT;xrbvujL1*{~iYqNHE{~ zouhL$e}~oE3w8jH`n2bM#J*XH^NOsQG4e#waLc?v?J~$-%ZhAj7LKC_sDqTxk~#Mj zgzUM!`8U{QWeH1T#V7L|;VOCd%zgv|5T!wJ?dPy4471)fGq@-QA$dh^rD(VMN3_+^ zL%T^t+hp3Qb>7Rq6zpFH8C$l80tMR16H3Z5*(AV@H07zfZtR7v}rv zoO2(FUzl#bodWoX(eIy4!RS59~h zK5lkoMYb^MlSHE&yk`23@PDZX7*wg#HWo0cdf{W(k6>K21~sE^Xynq~OiMe6asroG zwea#rE-TlW$WK}vj6DY4de`wNBx>$juAGenK5(hgoy)p~%^v6=T67y^<`)P2-6!0xAQ3;QDPe~d~R?uupN64yC>QRBU z^G2#%nA>mB$V(D3svD*xM{?brUV_;+H6bmhsf2a|GKy<3&SnE7H$O9LFt9ODmtJ(5 zd1-Kdg!r>{>P6n$pTb;$-abn$dKe9lrNyfdJ}8U6D}~QdyOwHwEPN%|R3COsbvuLd z{SL~yAybZ31vZ-^+4+9k$2;+FYAg9Xc$dP`>@tvsU zb%QbE5W4R;i$`J>Vk9sENvtFiml{5(*fM)Zfy|g8Q=lmm6HUfSX2j5#1Ce8rNMSGx zdI6U=M|BK;BXr+CNETdjt#GEBq!L=%2xptV)Io6uwN+wHee(xkWu#i25l~7}v07+rY1f(l)t*8@W z!?%y6xCW(}6xyN|WefVK9|;lk+;+We@dcf%hIOJ&=yqp)vj9xIxkDQfPw% z@{bx!hGa4=n&y6OZn$)@JUHTWironaP^f0!tBQO7K}EkbyfQFTnUaiYjdQs$3}>SZ ze+$fz+tFN@wiW1Hij)}HU^-m95-RRU23pfeL-5N6pbFP;-`1vx(aEZ*L;0Jw%>Gu? zw>28lJm+^r<~GZ!E9Us^9 z%~-~g$}4ygy1|-$xq_4>7*SX4nn(V;CWGBI4n~S6dm4qO(f&5(p1tz-X2&4eZ~huj HXIJDu^%zUQ3p ze$)8}tj@34036NFN%|h!dZlJ%wr(_cj^QXR_X>?8K;DWn+f_VVdJj+qtzWL0=b&^e z?c=|~ffNNSN2|WLmk1AubK>?hi~tcD25I~p7Wv4ncl8AB@=j@4W=~p)z4-&}P2{k& zEfQ&G1v!v+pg9i8vtII6nTunc#esP)v}D+^291yNjtQypn^Ia&%51jTUaR>cnyhaP Q;-zTr)0Y+6fhRxu3!9>1jQ{`u literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/command_name_for_method-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/command_name_for_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c6cae00a73fe00223017f58e45cb5093a9913734 GIT binary patch literal 318 zcmZ{fJx{|h6h%8AQ&A>VSYQf5f`xivd0oO+qzuh~V9H>`$die;@{)O8xr%? zz2}~zwO~yPM z9LJ|gn^yVj|9V?i6mU9t{e?jhTqf!c{pU0Q#0!&EE-Yb{59q^KFW@Bav{7YtV|24| zGjHP}PRIjKGzoa`8@6Tdz;m)Xh+bi<-F_6ECo2LrMhWVKBp2d*Y$-$Eob!57W@op_ bX?DCjtmLcccK+8XCWX96hb!_HlQI7Vlw53o literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/customization_module-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/customization_module-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..db7324177a084432e30b591c32949905634ef804 GIT binary patch literal 300 zcmZvXJ5R$f6h=EBw<2pnLTo`uu(THA?Gj#*GBg9CQwGa+oW{cTjr#neYe)jro56VM6~*wM~#kI?2}Oh$ZOq{4=qo}F#@#7m}kR7 zcuLyz%HRA8?MPiiF(qNNM7W-Hd+tBd1d!dyDi>E!R1^0xbPG7I25nSR-Wn~o?$@<- zS;geZ#l$SzctLjL9cYzjMm8$mYj+H6@Mu}&!YGCVljvf8pDAVVlTz9(nsRw}e?qGw U$6Wl4$d_7P&MRB=md}aw2MWz)q5uE@ literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/customize-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/customize-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c8b71f13f55aca14aba9ce988249a0127301baae GIT binary patch literal 298 zcmZ9HJ5R$f6ooq=QxU0CVd)kGg@t;)UBW9;hGsx8Ww30=X{v0<)B<6eW z_nmV#|A6J&3rc`T`?XV{$F^DO^D1A+=mQS=TM;0yWtFdM9`}6!sG~8@hI{`MwP}^R z{!4C2Swc2OVYEb8P2e4Ohd2TxOB|F9bI6L3yWpD{Toj!)s>*MS78`pKY;58)c@!`) z86KPqiOd)7G|Sm44ah8>e=L&B#oW$=?y+RUnab$9z)j|YvG34`)* Zf5a78T6Oti}X2Vp<`01$NFqj5`!vO!okRts2Vtwl^nQdMv^diBL4I=GzJTkb#82#|*)gElT;S&rPt(9Ynr?3Kp4xY0_i z?E$&AnRwhJCg!~tWJBJ8md>ci2IQTxyTE$y42xW7WUgn@*_hu4CQ!R?N@+W*i}~%{ YzFID`)A?VQoK*5+TG=>n_+(0d0grfUR{#J2 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/define_basic_instance_methods-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/define_basic_instance_methods-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e2816031ff87a41edc3a5dd00ec9fbdf6ffe6f51 GIT binary patch literal 319 zcmaKnJ5R$f6oosWw4xmg3!4!VEUo98CA=bKXa)pR2FrGC8Vf%nKS2C@+-757zW1E( zd>5+^*uK3u3Girt4j4z*cU!e=2uTaYhHe3u)u1#sj5@HKNDhst3Zz9J!C7oxyq8D~)w=tCiT=lWc3V zi^-#miOF{F1=*2zprtb^vH^Lg>>;q;JHsLu8ky^vbT;PmnL_QpDW&bKF6NuNBU&zV U&Bfn}yj1dX`m%A}@Trmh0@+DrVE_OC literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/generate_class-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/generate_class-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c0854e55d312f50218eab951c55046fc825785ef GIT binary patch literal 288 zcmZ9{Jx{|h5C-55$gRjoVPOkGDiWfeuS@ufl%W|AOc^ZOxg-{j9r;6ue~*i|&hOnl z_g-wiVEgfACBU=!Jz|(_-)+^pDX&H}=y*UTHTRwXd9R!DvE^}`0zezJemw;*QRyDt z-P!no)HM`K6k16Ox0yI{_Z=62m1t(tPZdpNCDMXGUq{(eeo Od6U0vt($o+NB;l`kzg7C literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/get-c.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/get-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..ac6c7e5b447775e703a7f54a8581116b504c1673 GIT binary patch literal 268 zcmZ9{F;BxV5QgCnD2*s%VPUgW2^Q-4SV9YxJTyZUrVN&oIEjVhi<~ove~;5_?Dsu- z?&6Wx@uL=dV-Jz{!3{hKiJH5fD`!)wFDZ@gr*4~DMxQV3FMX|g90ztT J3}XDQ{sr;IUi$z5 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/interface_defined%3f-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/interface_defined%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7d25efe3602572f2adecfca3e605cf531d2bcc90 GIT binary patch literal 296 zcmZwCJ5R$f6o%mr$gRj)U|s#}|7Q{EUCF=#H4Db&WHdLlsH>!zeFPsct2w8`36%ctoj z8LKed{WIB-x`tv*!W!w}cBb|`e5DZ}yJmr< S=Lz{z%j@~e)`x-5f%F$GbYk8B literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/interface_defined-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/interface_defined-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..587808d94a2a0d299ba80e75b4e3967fb36c47e1 GIT binary patch literal 292 zcmZ|Ky-ve06a`=gWFm?LQy0Wy#7Z*XF5xed2QpMe3>_@nxo#~SJ94hY>tmV`@c`$1 z=bTp`aJ_wv2H=S(?QdKq_}T@+WR*cVpmhNU2JCGoc-^afI1)ggy?^m)o}aVx1E%}G zi4E%nzu11V4cozL%Gx^<;dZg!Rr<;kK!Nj!fht(FlS(x2&)~AP&ZFQD-sw7=z&aF9 znqN@rMSM*9)ZDajbR>_c1{V&qv?-2~l=dj2l_r)afl3N}{BFATO7Oe?PL#gRte1g( JOru&ZHa`M|VzB@K literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/method_missing-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/method_missing-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..eeb096ec01b242ca1080d8e5faf94b4874e713d5 GIT binary patch literal 314 zcmZ9HJ5R$f6h=FsP?3?s!cvT=07W$O?Gj#*GBiU~rVN(tIEht1B0q%q_qYvH$E$nq zcg}Y)|Axix(=dQH{k!FUFm1CCmle8JrvWSBoX~v&$yZsStR|r!JU|_!{E)=C_aJ1; z?ZesmCMiou$3UfE2JR-rme@lW0U|FbuKgU+VkFkPW(HS9CnT@XqZD+lPn5Ne5X_Dg zOef5%rO77QLtYpqJRUe{qnyK?H41w|CC8@2%xE9u;}@6aC(rX{R-yZ+e??6c&z3L5 h_AXnls5I>Gd<-qpeT8n$i^WaJZYTfRSVgAV`5(t+X_o*1 literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/new-c.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..4368fa290ec642f0af80cda89122891bb072fb81 GIT binary patch literal 294 zcmZ9{J#WJx5P;zfmE*>1+NB#(rFLnUkHzUnBoFZrxf25djBOMQ76wKA_cis_^>p{> z-n;x8_Lom50gm?Ptis@0y4TwZ6Y^01F*QWkU`{IdLCmx`AEUX`?FiY_vGoKl@-8n#p7{vEpxDEOZ07 zbfXSzP`uT)pIPVK$O0EeG1oEaY*_f^N*Q;<7}JcV?|T)}wIg{>?&*f?%7PTQLfeNDyuj>-g2fV`GfzO8vY^#Pzx`7?6wpQ6TA zxx0UbJt<4b#wbur3%4`o$lW=P0Erogw7Y_=7`Y3+S-^GCX;f8yk6P@^g|oY?%8A3o z4B9$D_T(LCVFw*puXwA?$+OPcfdwv5G21a|O_**oq0oL)N}ENMFCQMKYLO+8&0m3( Pl=5bNSz9;oS&#k#J|to^ literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/operations-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/operations-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5db5bda02c41c53313f5b800a6da29c848e32094 GIT binary patch literal 281 zcmZ9HJ8!};6ona(K?R8gx^zobi7v(SWl3L=GLWGvQwHlMafpTE8~M?y|GtJSRp;~g z&Y8}Su>N?X8sORd9Hj54Dc5S2Co3AHMX$&>2JAh{lWl?F)Omm+X#J|uxtE}HBklbk z>z-v9EC;K;&`W~5vHO7b90q_03cWOb4vTa^>s>j4o3vG0=E;Lr)y`ZII}-__z92+3 zGM;S3_UsdQO1<);lh`P8a-y}=3y+nSf?83N@v%Opq^57qc{$0G+4k`gO&9UQ=KuDn PWcBU1vLM^z_>BJoMdV$V literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to%3f-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4c3406228db0a27f98a40d6642ee8ae0702c4c2b GIT binary patch literal 318 zcmZ9Hy-&k15Jx+pP?3e9u&_iyNK_!2`6@(!5-CG7pfY8!9Ou$lobAXTApU#OW#^jh+c_1_Yx$v zXs`cn*HKYGJcNd%FmN@&x7>b)0bn!*h1$;{&IfM2t7mYQcapG7Z%8&PeN?RUXkg-? zV9n%suuZg%c97*pNzZ!Zt<-zRI%^d3ydh+!W5Q@Z;>Rx}^POc`JuB0@TXhU$nk&3d pq!tufWP_Do++*^XbetS65BNOZmFdO*zVT9s%c-O?R`IDm`vni2Yf%6I literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to_any_message-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/respond_to_any_message-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..00248264202add954b2028bafa5ee6a27ca524d8 GIT binary patch literal 304 zcmZ{fJ5R$f6h=EBw<2p{=@x_p3-!QsyM$My49$RG%3#@!lUUfkksm_+_qb$3V!k@} zeCJ~G3ETHqlmJiebX0M|zT4_`Q|`P9GrFEdWZa#YRUz1MQ$DsljZ*|@lQA!b zhwz-V>6O3v2Ro3uhGI^_Xo;{}lt=Er(hQLO$to8&P*gMbF?1`qtOjjVQ{Eaa_U_lV zcUi{d*~Y}8d+>rB$Oq60t&VI`yw`3FZ18AV zzVqFq`3EfCUkw9z);}BcgW>H$9M}1|MK>DFi8n+E=Y-xpC6K&Tb^g%Mup2x;6Qo>A z>fB2ZlB2!+FSAOj3equjQZNG-6Kq56XBYt@IVjYA4rw`3>s>p8ld=~Q>-9)>K|9Zwt#m**^##lwCFBHF3wsI2y literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/stub_method-i.ri b/.gems/doc/naught-1.0.0/ri/Naught/NullClassBuilder/stub_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..902ffee13229af807fd759416c8b02270a62d6be GIT binary patch literal 295 zcmZ9HJ5R$f6h=E#rXov+(1isBA+-{so^O}%ij<)l5KI{?+i@DVenfr<@$Ye)1+m_H zzwg{LUwlFS@n$)|v-#PJFxalmuj*pc(0CXEKogaERn+^JC{-ui z{omUisw&9F$du$3Zm04+b*DH2BvRDEgau^fNL}#l46e&wDp3~?O0uoFAhsqE2tOkT zn;1`yp&j}JTv{yy83gU5Ie5}Lt4W|t31WM~tqG|ZeMH*@MwNENQ3Q~R32B^g{L5xK3teX3eHHgV@9e3lGn1z9%>$T0|C@Q zsb|H#e+p7{=&t@xu9LEa<>=%WC$w-rkvH6Zh7lmn2pSE|VNs0Sk#A;jQuI<`m0c?- zR^~ulnFwUZTr)Vz#+7wF(>vQtTGAT@%j~+Ew0`C9QuqVw00u8bncY=v>P|kq|05Dm zAdBzMs2y`3(|~c{PQ5f9;v^rK^CJb8#E?K5;Z5EuEyE{T@kg^T9~=h+95BjluY7%y ztWl;L>(<%6_Ka&;+qM?g_`n=%F17tafm29h~}PUd}_ArOJ$+86nqIlFS0xEW`?3-B7gTgM~y-QM3e<<2CJy#VoEH|5<)r_0Cy>+>k;GZb?&=qFAccM6HY^hJ^z;G(J?GdjqFeIn>Z_52EQ~FLzBGBQflpM#;?Y9XclSOZ!TALZ=Z2iE zD=&rpT~~x4tS+GR5gE}+Snv4QBw>_9d_abDsWh~75aCowZ=ib9n6ZtSPMux?gChPv$Lc+=zPwtFm0 z4(6x_AMoIoOxCu2!R@^$JwH|h7LR|PUtO~w3$)~d#V^-Z6ViJ-@5xE0$VR6$lsnSW zv=V=|9;NJdqiX(f5k-nCk;yKRR8tB)#cJh};aLr2DyRV(44d0_FOYG;?Q zAy3B5MRM4lM|ifIb^*mrJv?|qu8|K-=aCxpmT8rl&@nxxC-juQX7RV4l-u@itaP&+ zma2pl9xB`mGrXOvXLG6I2`;kdTu6fPHYMuSMS#U0_rw;eP_jeOGZxc5ag~K!N$luS o3%<7Hzs{fcWN`TTYw+gzNN literal 0 HcmV?d00001 diff --git a/.gems/doc/naught-1.0.0/ri/cache.ri b/.gems/doc/naught-1.0.0/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..f671a4d4b972bd70d76d8c9b83017089f812a3fe GIT binary patch literal 2902 zcmb_e&2t+y6z_pCwn=I?Y1%X-sb^u})DRdBpdMI~#xu)I3j@o^2aQ&%ID%bik+gx} zf1alg+q;fKoWgCT_nv<5^SAGV?rex26G53aQt8<+iT2--dU|CLIwP9XAG6;WH67Hs z7*9G$G;ChJ?xaa{G*^FD7sYu&v_7kOku%kK-5F21jrY!_xMoUoDYTU((LvMH1Epl@ zWgi7#hw)icv5A4uxhzW}at8+fwam`$HPZ;aVV7L6i@&OZQ*Ks#v>|T>o8OohH%CwwMcD!4Tm}Nt=66_;gjlFm(yIICtG>+c}K~w)^&-reXvp zYLqP|D~%5(5TyqSQs)3R5|^RK0Ce0m=Yke>&akebc`O9l@irwhS2EYL0YnF{cBjmE zKf8kcx%6dmdTu>ioDN#2!`A7zbsD*oe|;Q((v-pI`Z@!gW17AT)}HRB5c|M(h{{m_ zdPaR6@HJ7~R#DF$p%KM;-XCkk+e}cIgF;fH?Thf;|1}-I`o_YeJ*c0t6p5R8I!dBF zQdPwbmXJ+imb5llZHGZt5c)g5l71?{(5HRX@Q`{k!-A9yUrH4KeG*>K8aTS-e>*H( z%DkSx_joRHQ?)m`O7^4e;LgFsQEQ1m@wf_GFVOJP%&Lek;6EI=RRKE zU?OfHwOW&DNZ5Wu81RDGP@6hy)#12tgOwvIa1RS!co$!;mupsBS_K$uAds!bC?`>m zk|J0yOBe6h_FjnMJ!`i(!o0ww6LsT3?Liy&&jn`aw-k5R5yQ?cGDxDQp|F-iY!LqG z9VMj+VC++AGjF-nwTA zvcI0s@BfK;-yX0<+_AI#ADhVgZ6WcC2X6@fVLN!A&0s^D)(#MFqkaWUp(l?}-*8hf bAXVXZ@*^b-+Jfl8fSpECj zh_Zx>A=q!tNN_!2cRGBH13=msJ@&kStQd6QSkK_RXsyF4zj4;Al> L@Y+2%9i#jMFpX5i literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/cdesc-Header.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/cdesc-Header.ri new file mode 100644 index 0000000000000000000000000000000000000000..9258badebf7c4fa06d5b4a09ed702a859245d2a8 GIT binary patch literal 1158 zcmai!&u`N(6vul&Y1*{epscIlfRqy_7Ou`=8KV;s8k73tfPAnV$6d{wII^8>@YiFf z>6)@m9P{4u_kG^4ymFUdJo_pL06&DxF~8(kDL7(o5_sPz&Zu;NGrdZJ$(-dSr#Bas zUIWm$BFA{VoAehY+KHTn0Pi+ab%4wlp;Ke1DT0uudT{m)J2lV3=<1`6A zaF(8_S{(^&Z1;!iTQnjnlt&NQ+{R@^GIk|IYMr<@|OLPQkWBv2@&Ts(wPFO2#j zbYb6s~nbl%mS*4s2gZ-bhR$w4X%|xN>%lJ*?UB#nX*HnV@J*%?>qfO

    SsM}F1 z^-U*K%R8)!{RhA=rO;+OXl5b7pp@($YYH6;a#Tr%Y6-cc8?w5A#L8~#=-KG8Vz&j& z5Y}3d%?lEWC`PL8(ElT9W*EPc-xyd@m1gSOtjBHY@E7_{@ zT~VJ3`||?KxaEIZl?HTDa?H%eKI%Q?#bz?cO?%KC{k_Faf>WvRi!h#|L{fWwO$Pq} z@#x8hQrsTc$uQUNtQV9GmA_U(IQ+CF4Xhul8O?Mp;Ur0Ww7kTAy#ca%O67gd)#L0_^#f) z=iIHnq5Rxq53sX;2N@?Ex>7CMsvP9Vla35sRA>VM^47G~`b!z7<#Ctd1n@5TAU(kC z@0K(tC|nX+^$3qM;K2PkIe<({M%uW7qITTJ&@JG;9+j4D^`w>9ge!s}&y3A8VqpMff`xj%E~$Ws45bp3DT8G@7h+-iB7cDR_qYw?o$emJ zXUh**y*-fv*t*{x#*zANrO(@{M5n070*dFRt#047oeb``DUJXyD0=h&|0kQGIY2oj zX|y7^p1GayUugo!cCzT=63TiKK89`q7xkbGw$+W%ave@GCz0v(c#Ccv{n`xwd-#C literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/hmac_sha1_signature-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/hmac_sha1_signature-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8b1f417c3fef04c73a921719e3e21775986bf9e1 GIT binary patch literal 278 zcmZwCu};G<5C-55$gN1n3L!Bdg#{!;&3au@0TCGrQh_OhbxEDt!uCbB1LE!LHY?+u z?(X~VZ1x3VSXsin_xcB;B)A%(4f^k)2T1B*rHeDjiXMFo^#sm~P8(U}*G4zXaAE{u za+d1EJotvK*eCFUtd8Q?)NUU{=gEqQjgf*n(UObla1f0&^vgM~CsjVZy*sWJS^6Lw TL#MiIFUC}FCun#f(oIx3RbDys3yfPJ5eWcI6VYt&)gQ4O$D;;P*I-B_`_NZ66B*a_mc zlSY>aUoY=RxO>+E1iZ7Vp$Ouv6^{Jn1BO|pjS9BWa_M`YqX+}by7w1O_GX%))x`fo u-P}B{99m978pW~VB{mdb&!sZ>Nb~HoNT&b14OCuEUa$7(tS}oRyicD=_EMJs literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/new-c.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c88fda9e3b4ced54859afe3789643fb503e0159a GIT binary patch literal 277 zcmXBPO-sZu5P;!5NG);Krfm_hd3)cEp4>QRZeZ43jzi(m)g0H*zYwrijm zBUiGsaIrvp=Dy2JE4%^3AKZgTd$hNIk$K z$`-@*|A8GVOE?>X{*r_qE@#+5hR<;TNaWF?qZMSuAOppE0jEW$4OaP;(P|qfknl2* zw*3U!1jTmj4S3i`-q|o-U^b+pzxh&yrWbcg+k-MIp_7F%9l5{$7qqI57|6B R>9RSWS3OOa?~II*{{e^iUIG9B literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/normalized_params-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/normalized_params-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..20c8553f2f44094672c744cbe9456ec0e8e51e59 GIT binary patch literal 274 zcmZXPJx{|h5QaM-w<3&Hmkvl_DGb!}bx8$8WGF~{Oc^XExil8GFR~pF{CeDE?0Bbp z-{-lD#V0J^9;pV{+us9*j+%0*=0&=)Nl996Q zM##OZ*p7Vw&&a4CPD^EvUbK#k2(r>Bs1-HY5R1L2P}2|Ryqp#3d~W=Zr-`ryoN-O>f%)2OqFZ;zK1D+OnJwqgeu zg;qOTA-vqhFBPwC0O6IkKzi+ILu8(`)y>4)U z!D)j9z{)vu9m*h!!kQVTEdjF4vuJvjx>n-2YTN^0C)iDx+3#XW(kvn;vLrc#b;Fe` z5GG%5&&;!_0X*JlQMmxZ#Mhj?cA%G(QVDM>$rrZuDKh_H@o4?I;jI}bsHLNyP*!(K rOM{v^#+9I0(gG{zVN1DC_=?k{pGD(8Ydw_~qwlH%8qL&NF>B*DPOeg& literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/parse-c.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/parse-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..66f11ed43e614bcf9a15efeeca6b58dd5557d4fd GIT binary patch literal 256 zcmXBOF>k^!5Qbp}$bfy6RsMR?b};z89YY83iSmLDAT2hmJVQ2& z%IJn*nXrR&w{ZZ7@@TOSGsucK55AtjylAz-h#IZd{s9Y;QC@csc;yt^uru(2tPbM- z)cw_q){zxKDuaSr(NG^E?1e%@znt@WQsvKYiFm&QMHb7m6dUidc}Za5!>082`tH5&iTIj<%npWfabUyH01c{WB5 SbJ<*sRj)o;Wgd-6iT?rFk6da1 literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/private_key-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/private_key-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2882ca0c5102a9a9e19d2086938e5657b7c5f5c3 GIT binary patch literal 262 zcmYk0F>k^!5QP~kgBpeos7r@RX$M$}=VJ+KiO4`J6__$uPPjA{b}q6V5dXf0bm(|b z_rCYtjrK74{-6?I*<3d0YdYi;HO%6N)~b{AD2{kxz*cD%ziyRjHGVBSUjwXB9?-u0 ze_OCLh4EiP@YI7h(jL1OAgpu-8$W_5X{GfpAHaQ5DUDhDtW`00H@qMj`1AUPf3pQ! zupRJ(jPl|ds^-Uu%90UY78(UrqNK(LuoDGpI&;qRK^70Evuibpf_c=-hC3}Ed#g{f KM(TGho#VgiBUOF? literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/rsa_sha1_signature-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/rsa_sha1_signature-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..bff2c5253cb546c0570c6df4373ef3b833f79436 GIT binary patch literal 276 zcmZwCu};H43dqeN*A+!Lm zggbIK|4gq$p2NI%`Ue9sT#d{I-S^M~M02pzg&8DSk1qIf0_Rzy4HfCN(bdwQ6vY^s zWqVQ{TqRcG6J*9#2X$=fZtqp&*s6e)A;pcVxeM{IR}~rll~R_IBAwpe9apm?K9G!= SW1ZI*W2!fH7R{4E@8tndWm?Pt literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/secret-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/secret-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fb86b04f16d23b6e4277a446721c798ca7018a3f GIT binary patch literal 295 zcmXZXJx{|h5C-55$PG1Pg^(DK!U7BRd|pxk5g7^+A5#X)NiU6slZ$MJkAIKTFy4Eo zNB5p2AFzIXpc-J?|L!ofv@h3YS)|-!?JzK4k9m<^y_s&X__7^C3-E+`kM8>aLb5!E zv%#4!9gyI1=62eBjsrln#}50D0M7>Pf-e`a${J%as@7B+f0PyJNN?JseCH}A**l1g zIuq0sn*QKbsFK2CGfn`~>CAq1Rz_IB6u4M4pxl jxyrcYqDYrFw^N?+*pJVZ;+)s#bAe}aowoN@doTU~ypCNd literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d8f8b759db58b59c03b2277d69bba5dbe17ec330 GIT binary patch literal 258 zcmYL@zfZ$35QRHbZbcAN)rA4cEM=jduS+T*B12n=A5#X)NiU6s?Tc&&#D9<542<`5 z?|a{L{t1h>XKDbp?stc=qhqzuvy$HgeR3)e9vQHgqU8Kt+uq<|JH!s)71a^_{r}U3 z6$M=PUVp2I1h*q}r~KE@1Eht)qKk9L@?QBEstH`>tu|QlJEQA$xWFZ;L|=Co_@l4c zhJAp@$?7Q2p?0SrTTfO-RU4Gl%7$D_;2>)>^dp3*CMBP(9?sP~OWxV2n(m@mj#hi} KR+%TGLJ)sYXH(b! literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature_base-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature_base-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4d5715633649cfa385e502c4f9c827309203ca58 GIT binary patch literal 268 zcmZ9GzfZ$35QRG+w<2s*EDT6t02b=`x}*XkG880!Oc|_mdTA^iUt~KV{(IbJV|=G~ z@B2;`pRjy;5p+&-w*bFU(5ONv|7u#0IpC{31sq?Gln%ICLthu0!Y^4a8@a@kx= NRxj*(v=0_TkbgnoSJnUk literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature_params-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signature_params-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1e5d85483462d8d4a696dce4e6253ea15911831e GIT binary patch literal 272 zcmZXOzfZ$35QRG+w<3&%g#jrnbfKQFODZ5DLqX!ll)<{Bm&U^OMYaRtzsGGx#&>%6 zzVB@D3Cp)fZUMILcSo`3eZAE4D!&Z+;4qG!)PNps5Fnn)Dqp>8I~aQ1ju-$2a6KV*=)cARAn`^^E-oM|(s&H@49<&A8>;dfqnmX&F%)Bhtosw= z-Zx?+K0p?1byUZrc88!k&sIfj3@PqZ%Pywjpc*p#Bc-foRX)F49bbzq>1UI1%4K^s OS-r5gXdVoPApZapLRqW; literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signed_attributes-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/signed_attributes-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7cb5b9ab05a037c13a687351536ba3a8f37abe9b GIT binary patch literal 273 zcmZXOJ5R$f6ooq=w<2rRg#jrnz(76UE~$Ws3?*ZdTeY@7nrrZR5bl3|Sqt_}$3=G(F-IVtq+D-=F_9>14FDQHT zH~*h^tgfM$k}|p@xSAOU>A%wikb%jfiz_IqN%|Pt1zc8xHrSNcMyqW&GX%*D*^Xz% zgI8?FK7m(cbrh#iyJHZ8Co7^<1_ceGBNy{<5DE?baL(IBQ!a1sPSvW&`o(OV@4DN} OR=Ax!2bYuds+to literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/to_s-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/to_s-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6fabee13a81fab3b14e4d7c2bd664ac6d85d2889 GIT binary patch literal 247 zcmXBOv2KGf5P)HZ$Vtl@b&0AAD7>(c>ifUNr~rEl?Ct<|zf9y~HffE@E8dHzwR*YZ0Xd<*a?`BmE2>Aoj<4skyS zt!jkLES22ehaMoXgOQzIL7ev7dRIm8m^MnwB6-nD?A*jMuj*^@KS6piw1 zT&nKoSYy#J&xMu@8&+fI1MHZP8hm?Nsk)cI`GG(wF=MAxN;>aH${yk13v7Szk z?#{9g*t|Vi1+W``_ZWKH)*F3Z7W&EOE@pVBtWmSH8 e_bpAt`&ln&dPbKsb6H(4!w=RC(mWdJJ^KUur&|pG literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/uri_parser-c.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/uri_parser-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..7a17cb06b4f26e8fd9388feb6dd18fcff4a2bdcd GIT binary patch literal 261 zcmYk$F;BxV5Cz~4m0J-cmZ}Q_Qp5lY^?Y4Y6(TaUNKmE>mXltHRXZ1*9T5K>w^;L8bIWsR{|q<7X-D}Uh?>FBT83;)EG zSc?P5jGPJTyfodHR}GU>L01+PHL9jAMA)keE&WI-%Sn;W9v;upEQ!sNv22|4dO5b* M6FY6UR(mi10DJFM4gdfE literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/url-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/url-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7e438cff605005862290c9cdd00043f93cf7acd7 GIT binary patch literal 245 zcmXBOKX1Y?5QcGvDn!kSSXv1wUD~C1zAiyP)C?4fmMMc}2dA-m&PDzs#J8_Q)_Zk7 zJrC&_7N;FG0Gs}HP`;x}z0mV2PlLq-l6_g_&)?b%sE(W9JAh9mF3P@)^G8yakPShi zZU~+x=OFA~7yu#~jOu*~SuqIfT|I-xqSdIXe1%%B-CgA*BD?PH>bsQ@{Q*{x(VmY- z-Tyk?S~A=ViHcLp8|r<89hVB}${4F>RX%@x8()ho24_>_*w-wlsxPue;1-2*>>n<_ BPEh~= literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/url_params-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/url_params-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b0f9e7c0305d2cba405b9510f1ab86b318260f44 GIT binary patch literal 260 zcmYk$Jx{|h5C-55m0J-cmZ}Q_Qo6uGJztkpKtzTXiH|9RbxALcRXZ2i4v2q`+boQC zy7#$vI{$*j`!m-7+wONqq2)ul(6b`F8Jtl)I<#JZc*%=&^`UKV=xsZM7T}feKyLN# zY9sO-u6w7yF%ZM;$nMach8`gP7%X*R4oMc-;L8bIWsNpeq<2PFYk$!dW8~NEMSpaa z*oaS%8CxCHd8xajSB+z<0#=3;H>&0?MA)l}4F5q5uE@ literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/valid%3f-i.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/Header/valid%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fe8b82a24abc34d5f19534aaa7a951a03251e53d GIT binary patch literal 263 zcmXZWKTpFj5Qgy%$W&ycVqu^P3oO+0RftqTM23RIpDBZ7I~QVM=OWtyA;fpbZ5Z#> z>8Iyl{sxQZJJJA~{(FnDqo!V%!z#}{r8UhB19o3l`PqwcgT<%K7(0Lmlnwgx|Bp2* zOUQ;%S)&O~Cv7YJ$2b5adUV*wIb_8keGK&sj*8Y;OsF+#7515Fq-&#L_RBB1sd!}5Ch^Lx2tiY)bKQ*ydX QeKHk3l6TVHS{VZW10`cr$p8QV literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/cdesc-SimpleOAuth.ri b/.gems/doc/simple_oauth-0.2.0/ri/SimpleOAuth/cdesc-SimpleOAuth.ri new file mode 100644 index 0000000000000000000000000000000000000000..acbb5ebc63346f0350d0682e01c3a15472fcbcc6 GIT binary patch literal 356 zcmXv~O>4t249#IUUYm|V4?FBI$PZX^mM!DRxoa&IhF`JFY*DokWGsex^EK(#}E?;9rA28xne6YH^Qy01|0 zJ+*aIjm4VwwWcl(2SVMTrJq7v7GhS&WQtU#RX)>Jg)lNnE>oDhzOhCRcnVj}Q$!tc zH#?u1VlFF#gG%pwr9hSqm17Oupamfb&{K;I9vS}#mcPA O^z!tf4Y^l5qWuHsO=#!< literal 0 HcmV?d00001 diff --git a/.gems/doc/simple_oauth-0.2.0/ri/cache.ri b/.gems/doc/simple_oauth-0.2.0/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..9b6799aaa21cf8d07e5500939d1c2d7c54f7b77a GIT binary patch literal 938 zcma)5O>fgc5bXh(G;Z1oXc}>fEOBfVIHBzUA<+n*dLW!~SWVVLvasH@_9F%Q=b80} z*hK+xv-i!sc{6Y3$>8Cfoq`tVys_>fD~rh|SvLyr-Uq*7>?1;jHe=cCd`Vz_xB800 zXE)h`oq_jOu7bzE=iOxU<)ADsV<@*R*R)2zF;%3XVtv3gUK;HZ@+hSN3v~;yXF`E< zJdymn@QCzQC`^S!IWLPB6@G!BJnst8YmT}L$0-|$DGzqAex3v?(f#+9RDr+=t_zW?Vd`0da|_qbO>x#ReJ zps{0bc-$=t83e1+7ul+!t!eED%C|I^>Rm+HaZPQ_*hy`wKn5?LQbWC~Nel5Eqp2jDPGFQ7J$OA)MvWFAF|)S{|Qxmd_q+mm>yy=(2RlZIc< ztevz$?FA)@+7myj5=2ZO50}JLCLi>p{M*-+i!>4ioN;w z>^awbs(G1tRHpeCqf8h`93UvQnu!z*aIjj;1kYj47hn~bJCMNh91{95uE1d`W+*|$ zzcI1k5ximNJYK+@W|TrsL0Fgzo6*VfEsHVOj9VyCPe=~~<1^wOS5GJ6_Ic zIv#SZDw)zXgtQR}Qy3o@lZ@!gaMZaS zD1Xygu}M~Z22;CztH*fVk{Rj+B#LW;U2>2Jr4QP(bff`z+8A>LLN=P$cGM152G@Kg z8HgZZf&y)(QgYW>l<^so5-VdR(olCu*dvH5ClIBFzV{L{#edYZl!y$q>m`wNTr4|w z$!lXFskA2V^MzB{r~+%1(S^DOW_pfJ@O&v2d3CmyTNmKl1~IzSB}y8KvR=WJNnRPp zP)HYNo8}@u0*d$&$6;n|X;{A>S5wo|RlMj@Y^FV>r+r~eg{J@E`1rj;!M1{l$Z^=| zQICFOY~&KsU)z#2TE&tBHA6 rt5?}qNB_n$c1c*sr?4$HXf^7W*v3)}FW3+ElfCABHd5s&&M^NAG3>w@ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/method_missing-i.ri b/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/method_missing-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cbcc78ed58a247d1f275b7138a733bcde68c151e GIT binary patch literal 320 zcmZvX!Arw17{zyxI_z=7gL)Vh#L3ut{=8J2gB<2z&QlK|Nz*ng$ybsTnSZ^RMG*1$ zc#rpc?`-@I)7=^cz>__0WoWS~r|O(!6Z0*oQQj-tB#^vpNH%{vTG2YR>Qh#0sb#|g zy4ye5$7H{OwClN60^xe--!gaTJAer5jkIA5Y0)tkd^v)PqE=dxY^fDrh1N+{QO|0* z^1pDj`r$1dPa*^I0*wl^jqy0q)7qh-fpIM<)>NPkk>e?s8b9(pFGnQ1xgWMJW)I9Y ielfe_8pUCL>MPPc$*%r=c(TRiaO4%8VftA!@AEGm+HDH} literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/new-c.ri b/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..d42f7ba57a28bcb981dd4d087c75eb26c05c086f GIT binary patch literal 281 zcmZvXJ5R$f6oosW5H)Mn0R|*bu(X~pOArOgLm42QGFY~A(-<7z$aYkfUr(Y6iGle% zzH_ef1FYV6WB{K0d5@{1re4`=!E%qM46>I>u)B}5H(elazp>e&!=p+R0A|NyR#i|8 zqjuI1++M2oDtwItz|=eT=u-|wIjE3gy?|xeT8DydoYmXZ1yqfUs>N;m1Ch-yWfSzw z0A5mWlk6tD^~WgNK)p;#JCxK)Lq1KMC^b4dan9?7V9R^bpAU1oEM5h>`S-;voAqV( M8--rEXQyK1Km4s;Jpcdz literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/setup-i.ri b/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/setup-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..38e7b9659a6d39ef68de43b8551646a32da33829 GIT binary patch literal 281 zcmZvXJ5R$f6oosWv})Fhp)4pYu(X~pOAw_}hBEM&GFY~A(^z$UBl||E{CZqPNDR#9 z@tt$E_=MHljtsz)KOc}gYU-7pSH&_Sk3$C8%f2dZ-_PE3fxP|3W`_=siYeSpmdEU4 z5BV@^XAQy4)OJweG!6i%dhF5j0`hWDfnz;`W!YMXRk3kaZ@CMo8W~lK+xUkfn_tW( z=qxcnl+;_6U9ww$jIs^XOIF&Uq*fa8oH$Wxbo3>JsAp9%zkj$y%RGHp|NG%0o9k)w MD}`RUXQyHmKSSAGV*mgE literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/teardown-i.ri b/.gems/doc/thread_safe-0.3.4/ri/SynchronizedDelegator/teardown-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fd22760856622d262b7367a2b3290e1459cbc3ee GIT binary patch literal 287 zcmZwCJ#WG=5C&j|Dj=e6h@suW(k|fnx}+*a$^b(@rVN%pF2us|MYbaZzaAshszc{{ z@1A?_Cf_joSd#*Hb*C-HmUKNcbl%OHE-RK?=+*0*HpXIAEUl5N*m@M22hrdv{DHXs zk(OR&$pBVTXCiM?+_-(MJ(rZKEXdMH z=kq=9d%ml15A)5F6#%c+Ra`GMZyI)^!ZaE^I>(O$$nz?V=DUNFyx8(m0-Oqz;Qj9- zN_H0RPM|e+?`;i$)V7kwhcHfR?tH_Dr9ntTHh@u5DlOA!p;i9idvw+y``+aQSr8|- zQa(GNq%vGnPOKm@6I*jQkW&=Egq4C?7O`9J9wnrll&KmVC zi;j9$r^9514gadMfCV_2=)R)sV<8J*T(`Ma0yP4d)y{e;ye#^3Qakm*z3h@Snkv(H zZiGCy(s5UylRi!{qRsvJvzFZ`UmndOPg%o4HHa@p`@u*uOQY+{0ua0si@#f2+oIL- E2LkqnT>t<8 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/%5b%5d%3d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f39380928ddff8c93b0b6e0c09ded56360aa8b30 GIT binary patch literal 319 zcmaLSu}j1-6bA4cq!v2~hl|Tm7X|S$IXn@nr-csZaGq0(9polGn1z$-Z^Sns+8Ko(0=0u|tUtjlc~P zEj}~Rp=qwBmxrV*Asa@nm9TI*XK$J7#sMHgV~-}JkQD=S!Pg5oE2Pp`<@Z|gbvR1Y zM{3QE5_NwR6_Z8zjNLgNtv!$;_6f9&1(o^oR65(!z_>kbdMt8b=9yqQ9ZEUsMrvus)=F6J$7*7ZzpH1nSP0y!OOV*mgE literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/%5b%5d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3340431680d808563f130a5c93aa5efc3eccc392 GIT binary patch literal 310 zcmaLSF;BxV5Cz~4D6N{c>cWD;0t@lf;aCENNEymd$`m2XcFx3#V@I|l)PIlDs4M%u z``)`*eZl7VW(B~DIUg{zwy8I2S!K)mJAvfAtg`&nI%Lf!lNhgp?Ugv9M2AM;o{1J; znds0o_c8IDlqICY$h8s{Zs*Sj=DKkJh|Jid2`fm8fw|!81*{9HG*;P8E1ri7M17QU zc7dq7N>oe~<+JtVc(hJHidZMmHuh8I$5ZKSPXpr`sg+b%6QbuSM{R!zA@!ol)(;(? bAE$JY#&vi9ESlzs?L6Ycx}NF1X5N!Otzl<( literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/Util/cdesc-Util.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/Util/cdesc-Util.ri new file mode 100644 index 0000000000000000000000000000000000000000..63ac8458a9a7545972811bc726be46bb2c9c3dba GIT binary patch literal 466 zcmb7>KTpFj5XCc~Bu!fuBpBH80jR}*(0M5oDrG1`|4be%$GK3eP8>N7@bR%zRboY! zPCA|6d%mBq(gWOW-;4zKFt!nTW2!+TyHRP8PYzD$7~=PJkw5Q`7DcraH3Gai($;?S@h->E{Vt zch)$R4y&=9byj@|hoLF*xoUeS{0orVFOjdkv8#Nxwcg;jXKj|13wKV@2$s)!hx zq%>s_oe-K478m)GR^`Htym;?{EyT!++Y2x*12JBnkv-Tlq!;<)zZiSXTHgNsyH#ND E3)`%dTL1t6 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/cdesc-Node.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/cdesc-Node.ri new file mode 100644 index 0000000000000000000000000000000000000000..3873b64e65b649d6e6aa5ecf41465324c1acd11a GIT binary patch literal 1938 zcmbVNQEwVY5cWd_7_g(twNtfy*dpZ#LQo$nbx%=nFf^ywU>R^9?%}kzH-s(6?sa#8 z@b5djXKd0YO6ik*vorI}H}lQ#O=U_i?yeN4bg1-_Wxb3U6P<}l*f<`l6iT$zAB2rx zCUXre9kUrwdTG^C@H?1+2Fanv_#ECcz5toJG#C_=Fs3$2{seCEW1{Gf1;`E4i&ai3 zBCeJoZH3mlIn&leB^8t_K?VQPpFZ`yWtx4^ET5O~xf(VG?_v9L&9W5`%%Hbz;xG-_ z2s!nSd-MYDStjqx=34Td^A%+N<3eGGLJ7*S) zlvptl&W;u!xmFyEc_{22>rOz(4v6*!qQp6tVNO)GG~(bX!J$)DPc2<#Bij1;YuhPZI#Q_{P{KU z^xCe2wA!7C48q2*nMht)FOb-vLS8X1kXY{&5_2b!I4LyJ)`<`AbWuh&o@4z8Wa61t z%h<9cgILXCHxV4Ki4(}wrV~^x~p6L`18F+*zfHOSlG21Xa4KBsg!-acrrg$ybKZ3qn z$Fspz!2P zBl(^LS<;-=jMwza_>pu4urn3i{jXU?Sq4|FmEX*hftwM(W%k&$0KuheNc$UI5F{;K`QJDmp-t21$=~u$KDMp|GYw&q_sT w1ahN&;5jTwnV%#{ib)<{-w*lYt$gS!(peaO(eDXY#uuaV&e(>jwPMaCClU{D8~^|S literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/key%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1ecc75970a8ddb0289253b1c591f3cc72ac24b06 GIT binary patch literal 297 zcmXxfu};G<5P;zhD74L5v9N^&7U~J4>p-9oDMLGyGG(xA=S-|Pc4Rw3eS4fl9Z$N` z_utL(2R5fqD*)cj<$$5Fb+u8qWwvVZ@|HmIRg~H5xpBzqZzeJB1=}fcLWvHIz&#TU zelXFZsR53*#)s*0mlOr0{lK*n7Vc-`z+5}@01+HIG+_y8-ZK|`wSaXlmBuoA(TZ=w z1X3TxEt^2j*PUZ(KB(n6VFx8EZrQPsd?4BJ3(1~M z18}kp-_MUv$+66mD&874<0Q0_7VcK#om@YS01=!9HX(&gF_H`Zd;wQQt29SaE3pd; zi$1zLT3B>{F3K53vC0olEL2{^asj*8R+%r4t+N9L5}MJrD6I+6^C(!`@BCO?m)YaL Tw#~cb?K^D-h6R|F&e1T@`wr@T8TR@ zTYTp+ZX19DHTZZfZ$}glHg&I_S~I^9w4$qhc+xAEqd;PuV-*qC~dIHHb#qe zxR}gGbj>d&b61qfQDtIcUz|v`$qDizE(@%UQ?>o^OgZXU;KCpy#U$AfJkfW>3OUcY5ekb93QVz-cM5x}UuC->{yk132F8=# zyYG8v^AA|;UReS>+n)^u#a*+|=T&xXSnjD43cY$tAbBgRtf-YE?B21bm=8Q?xuc#O zSxIY@ie4~wYzMIAE=K;nSS4i*R|luRFc8D-MBSj<9}fUg;W&^Db4ZH=y5O4`To%1H zRArAwx65!s3m@4_JfVgAV+%RLMLW?ST$`+t8uB6v2BD&{wx3?~jt3F2H6*wfl5L1Q oFIqDEo#%NotFrWNoO?gki!=_t7!vFvP literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/matches%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/matches%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..40d77d5fd6500fabd30b36d414e8be7091e83654 GIT binary patch literal 311 zcmX}nF;BxV5Cz~4C=@CrhKhv+g#{!;GcjBS0;Q2Mv_mOV2J7rxa1_UmY)7d79;XqE zC%wDx-P!yLmirGQ0N(U*OJ16)TsG%LeAS^BlH6+q(IzkA^dK!^^@%lwtT$aF_EeK4 zEohA)`HrF`T>SMwrJa-2MF-ck@j;~WIbB%${Ac{b)%?= zUsS_a{)93Y)D@mkX8%+sMwao(eYQMGqXQ&asOFgrT^s%FSZz(mJaR?M)Jz!dgXb70 rWqy(*DQ87|{m|0!=}w}PkK>JO5&pdx-w0DKZl=yVV>?u9h0Z0vzf)&e literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/new-c.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..ed2c2c4ee157f89b59ac2c9f1725aeb2f54f44b4 GIT binary patch literal 326 zcmXxgF;BxV5Cz~4Cc9Bw@38Z&|QvD9RAa6A^Ms{q0C+%|JY53W@0mH`)i!5r)bfi=t>2 zRkm6Q>O`LQc*@fssz%IHjlZ7g&?0?KwN!W0?J@~JxSFa>t@zE{WoPU_)kab0ia+i9 BY-a!f literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/pure_hash-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/pure_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3760e45a2110cca043bde73c3288f7443fcd4ad0 GIT binary patch literal 304 zcmYMvu};G<5P;zhC@nU$|`#~N=K~uWG%(zU^^ua)RH43 zXv>78Hzv+x8i2iR=>GqFlawW-{lK*n7Vai($J}}70U|wgWWoZ{qGvAndImQ|t29;F zvsQc^E-L!SuGvLJ_s60bUE~w|PN{qAI;OXpd7u9RSvX}* literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/try_await_lock-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/try_await_lock-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8c2f5847dd2e0ed54973b27b8d86000e2da5fd65 GIT binary patch literal 1003 zcmZWoJ#X7E5Y14y`4~Dh=+Jh!x=RAPiKh%Sn%Z&VLdaK&b_f<6g_Scv zPpp7pB5dq2mgjgvr7`0vR}~AP?<(}$2~K!=Spu1OT@UD)SuHCr_R2hJ`VjXBOOhoT zCH+w({?FVqjb?GB3~kxrZfo#p#%@XL9C>EV8H^Dh4Qd^awjzf?u^bl3XC7=xIjj{M zZd!4tl8ecC0S{4kPJv{I&7s8bhr{eFWYjp%>*Pbbo|TC<#E#mIgC~W&@Pgf7s>%2s z3TKyWk*SA_b-&+0i{JwWI_yJ(#99F5x0T}c#JAAnSBq8ZH%6Au8uf#E4O4tM4Z^#2 zHs)=sGiNcE=tHmeQtXZj){}Hkw91Y{osraYNRF}2Na}utB$Y8GY1YK#$Yqg13`U%! zkg||yu}|YjX^87gZIMcA0tdsV8ELy73Px# literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/try_lock_via_hash-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/try_lock_via_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7dd250ee0e37cd6454bd0062495acb05dbb56217 GIT binary patch literal 342 zcmZXQF;BxV5JoegQ0Q8ffu#ydS!gDPtB?XMkutPHDN}}%<6MXp$Bt|V)PIkYh>7uZ zx_j^Yu4bRGIPEnDcvY7JxmuU`LR@Fj(wPfN%^Um{3~OfV5W@E~i}vT*5Gy}eMgGX? zR`3&5WJqz^F<#Rf;|-}2;HXP_`2S`brYX$3zL0`zxS!|;W}3bO@G5;v%FSS&bj&!L z2XLEILQ)nzOHpjxNJs1O8#dC>{Na%gd@Lq`CsTym@C=DvlSA)KF5zMKLawP~5$NoH;Q E3%&_*q5uE@ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/unlock_via_hash-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Node/unlock_via_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..50639f7efbbca273c9ff7fdf739c290640e974c5 GIT binary patch literal 338 zcmZ9IF;BxV5Jo$oP{_Qaj9MAqu`h{Cpc4^9Z$+7Ij=~Z)@7Pi}@urvj zKrLC)oVLgXZIE}Q8-TrO=U2YAt^EqP&@YA&zK^oFBjnvP7Hh9ZdGi!#mk!V)&0*izW{rk8w2 zEm_i>Hpm6NBJW5y0DG(zJ^VYdj*0@}!%!>94cuSQE!u840EB{}C+(*Y=LfXjRTG%y ztyEN|&q~%Sf0mgG^a{^1vwt+>qs{6I{$%TD9ql2@L!W0N1WWzxSZhts{Mf}z%ec`# zc#hSi%rVQdYEq_m3%N`LISV!Z{B;Fci9duA8(BSxHop-YOA<&^g?D;zOH$rFoERzk1GFM_ZE5k#5)A| z>dhdtJ>f!bDWUnxm9Ywuz&l zD1%zh`XFEGXU95g2IiwTW;!N}_F=AL4Jvae$Voxg1zpW2rD=#k#7H6&&1ednacYzl z0Z-w4w8o?G*v{qYXyps{7>g=DliGP6;#peBhMq*=z2J^%JTPtA2!^2k&sik9Xi=fZ znTv5B>BBj!zr%Q2}#1j9H56Uzf~8Xb_caIa{xTfS-= jlltWWo`Pj*G|l9ySU%}bZb^AwVJ_x8O4)GpBQ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/delete_node_at-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/delete_node_at-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0e44ab78bd4b732bd53a9e0ef165fb8125cf753f GIT binary patch literal 341 zcmZ9IF;BxV5QRISP_-i!3riFhkSdyq;ktwtB4sE;2~&oXV_%3>$Bt}Ah<}fhh=uWn zd*Aoo)$$WI=U2l4Ui8n2d}~Ctk=I3XBS?`a)J708A3^k%7s;V)Eiv)I8VVoYbdsN` zAxoOmk@1!ej9*9#fRfdU?*E1CqdbRoKh#Qc19vm{#O!700fNQQk@ibiXFaptRSQ^U zjZ{=5&q~%iKe5pT_>N6%w105qBOU7*|77cEAC-`1!O&wHl%@W1*jUq{AI;D-$c^@a z=ddPazSA_V7DW<2$Zb59-p0KpL7bd3cADXF%*@tdhSk(AoH@UpOS~J~F?CeTx%3zF ClXF}E literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/try_lock_via_hash-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/Table/try_lock_via_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..14376a2c2e2e53a4fde4d698dc52298195c53ee8 GIT binary patch literal 346 zcmZXQF;BxV5JoegP_=7S39+ECfP`o!hU*e2jg+AsN|-X79Opu;ICf+^p#FQDL`*Cv zolf7qcXze;g!TDdbAVTMIg)F1RjkEz7Hyolpwzs@Z^5u(wh19Tq*-*x8$+!6U^V%W z)1BaFs>zVzv}e4bH^y616+q5PN%#Nv?7}pKRX>zca1FOJ{>V%_^Z?#v=t#K*tdgD? zXNv%qNi8I0(Tf!2)=hY{p1)-i9?c&g`6z(pZ18N#a2MtfCtlKFS9smFU literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/attempt_compute-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/attempt_compute-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..704b1b247f395bcd3284d0ada32bb91661fbfe5c GIT binary patch literal 389 zcmaKoF;BxV5QRISP_>K^3riFhkRlohiNR$E6e49PLn%`S>*8F9RmYC(OHu!QoklDS zEH}MR-+Om4{bJ$f%?QR`^l^>Um}(cw%OVbe2-}XhFm2Zp1}u2bi}-olScK{mYV-)1 zR*DVQXi*DXfoSj*#2$5Z`xjpZdCsmnD-S?u*v%+igWdNXW4=M(qNXXEXB}8_y9t|R zwNzNdPfC^xI%~P}-UXbs-2QsG7{t6B%@4K=mcf>#nJ-7Y@olC4cD%NxEMX(IEB1wHfhT11qdhejJrUk~LAutt4 zquF~73Tn)Ek|euH9*Ktoo#OC_O;2%HqpRak_SP@RV`m(yIMk-}zrzbd$>X44( VpPTriOx}!3e;C_hvue<}5(GEEDIQRbR+t#N~*#M!WAjAv|Z_ z`omK(OFOjeb`x=yR;r;qdT3O!;3Ek*kFvlc3D{p0kOK=8Bg~yGf@QE3N$PnSYA>Ml zr-RCx78r|$z*Jt@%WHN}P-DK6B#$OTYB$NF`+)m|b9$fWr7NLBD z3cZ(1BgGmkw5SCxK-BmIVu!lC`7>u8WEneet=t2lVOImj3hb_H8S_kCgPO){lD1&U zZAa`Zt)#*{dQh^M(XpR94={sczbE_w;G!qs#ei^ci(npXSdw~5;ldIQ mH4bGQYE$BHc`v!^qtb~VF#KmUFUrK_FvzR14XA|z=aO%Z8I^JX literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/cdesc-AtomicReferenceCacheBackend.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/cdesc-AtomicReferenceCacheBackend.ri new file mode 100644 index 0000000000000000000000000000000000000000..feec86e553d59fc7757eb788f5d5e2673b97cc75 GIT binary patch literal 13767 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 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/clear-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/clear-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4f47c802f5dd6d768c56ca46a5124b1d14f6b18a GIT binary patch literal 420 zcmaKoF;BxV5QQ0#TUv>!Vu8U53rMJq7#Q3oP>2+yBGi^CgLQE(jaA2vYzM@@$7#gC z!v4N{_r25c2b*o4jbQ9if3MNkrp#w@ltmMv5G-NjCC#GyU2PG{EmRnS-ZWBdutJMk z;0i>IPaqDc%j*GJk~C%0wkwnrhFuQ#*I*A_%UCGu8q|Kwrb!FdyPOzy^*8el7WNj} znk>(9l0~ms(<E_yLu3}$m%9Pu~_@}AcL3&$O=tZBH1LLoO5 t7e@Q=q~irD^A*Q&ev(C_o7)~u&cl%OpYcK{6&J%0Z^kyDRtlVpe*m3$jXeMW literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..db1689e49b4fccdac418ef59cc7325b3f3d79605 GIT binary patch literal 361 zcmaLTu};G<5CG5)C{zt&#ljMWr7Sc9Vz{azP>2+%?NHh&gJnAxV#To|+X40OaavVu zjCZ=bcXwCg159`CnghJ5;|5)=%VH|7^Z17Aw(A`R5PW2L{IstP((;p5=u4e$1>a$X z1{KE@V)FKvq;%OLD}CI#1UcQ!WEG<^r)!M;W1#t^0*HO>|zn531En8(jj zu(>;F#CmQ{PZ}{7j_|=F>Xo{t`C8b17z2Wmz_>>fQj)$`G=Dy|4q5ZTB*vp) zdnJx2(V-EzW1_`ZCOS0D-QNe>w5mupj9e>W$<6HUnd`=ZkQid@BeNh`IWQM|oseZI zl}4IBX~j3;;)0LxhFx56zc7eN20qh|j;Gu7M2a$|3(&^6%6xf{&h`)(*9caEuqH&$ s14nJYi-P9KbX6xbU*30kewd~*i<{9 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute_if_present-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/compute_if_present-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c5af8ec15a967d3d01c4ee8d0d5d88eca47f9f47 GIT binary patch literal 383 zcmaLTu};G<5C-55C{*oQ!N6jLr7ScPgR826LZnD-htf_NPL6XSRvbIB9Z=sMrx9X7 zjAxzi`|qyCCptU4YEJ31I`7a`y2xhYIt_2RZraWvh!R?Z7L^NV@Rp?E`dArc#XBp} z|8lw!{D37IR2(;qSNOtsjjFi+W5O~>5;|?WTnet~-5~Fnsk@d^AERr$Gp5tHWyaZT zL?>}6B&Ok$6#2qkV6a|ZunP?4M+V;0kPr5w$%AEZq*3hSIjDSIp*}2>MmOMCE)jGI zTr1~23pq;t6-8+{-=DTyvRV->3;1NRL$W4HNJ4*K`oY;K4JY#&&kubSPyJcQKd10b R3BMV(-D}e@xslA;=o>pXf#LuF literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/delete-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/delete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f8f6c599dff66c5dc52816a2c287a72529d8db75 GIT binary patch literal 318 zcmaLSF;BxV6a?T7$gP^S>cWD;0t>Z-#PGTV3Xw9Dp_D0uWjoKriepE%Bh-J7+rY|x zr|<4+@d>NLtCIlF_O!>?x~5*~d6j1k8jMJQyp>h{cx*lL=7TFt$>@4552(QXjo;fBa@4*YQB}bq|niN@^HfsA7nDVY?kqd*&DJGqb$qP)Nao?2EdRFDj fyADtH=XQ~$hd2McN}*D&rxWka_uT9Z4}tyw!C7kc literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/delete_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/delete_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fdea7502546e5d106d64ac8fb067433d9fb178f7 GIT binary patch literal 335 zcmaLSF;BxV5Cz~4C{$!AQpLhjg@sCpWcPpX+LFg)}!^VoUn_mmWqnx zK}o*yClOpAS9lV^{*oY$Ch!rxw>(-$dzNOQmxm@4mHN{`ZA}Lrxgsz%2%~-Q9B@+R rJ5AGaQY4qREgkL_U#JFJ9-m}!SiAUVVF=~oYTWW>Y=>&2(7E&n;V^N9 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/each_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/each_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..881ee97c6af01ea8fe08fa212f261d3c76370f88 GIT binary patch literal 337 zcmaLSF;BxV5Cz~4D6NPDOU1%cg#{!;GcjD3Kp|3wGL$l9u+GkfSaIygc0m32IE@e+ z+YRsZy?3_wfaU(h2!JPj+>vigRW9YcNG=FP!+Ml9g6K6blE*`139EOkDTKZ0q}WqU zmb9R4$kH>4mUMOV_qd7j9O8c9N(uwlle0tH4n06XhmN#gK%Dhxy(?#Mp4C!Ou$1I$ zfAW|M;2KXJv%eq{qsaI~K3E=Yq64H^XysWGYD)d-SZz(mJaR?M)Jz!dgXb70Wxmt2 sNG@AC-mkt;4K)6jvm%+_-i>D#hsCRZR)$b6uBJtA#&)Q-3Y|-T02A79m;e9( literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/empty%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/empty%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..18933b062cd6cb532cd03790f697d1e4d2716dda GIT binary patch literal 315 zcmaLSJx{|h7zE%BD6Pm^bzwnafrVPC#PD_?P>7VF9ZH!pShn+;SoKF_J3{^UxDBlA zcY5xwW}h(Mzc~T$VozI)ook!9n$|^*rjMuR46^sCE>?%mBWpjH#FUKAD6vP09<9I) z6CJ)XaYWnR{kGOwRYBelTr1(=W)!x}ABP?waf3k{XONdY^D#6NxGtsASQk%P@nyVV zG$d`wE*SNH8Wm@b^3i+rJX>c6AZ3~qX_q!C`xU74&d|uXM(QLL&c@^g%2B&-LP#^I ei|PHtxmxDw-t9k^Qm7J(@xjh{!}Lb85XcW>CuyGm literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/find_value_in_node_list-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/find_value_in_node_list-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f586de4bddc2e90715c3cc96d1a26674cdf58c17 GIT binary patch literal 376 zcmaKoF;BxV5Jo$oP*KK;1%?n7kRqCi!Ce9^kusE_lqtjM;#`Oo$Bt~LsQMEhFqhoVlFQ8=&ly3f<4NCKqyeUB9OwmfCcYa9<6tcA*?>J zCV%R5C-|0XGNd@IkT>*(yd_mV{1vkdvW#8#M(oj%X18aF4Vrf78S_R%N6JmvEbY-a zTTIwhS_?^e^dd#Ma3?%i&tKpP59XH-d=!B4Z18N#U>WRKl6px8jkgx++d^%02M$X~ zplje-InT3DlGHy*k`$9Xx_=yN$6-r{IBd{1ao7)rU>u*u&~)Zs5&l!(FJ=7Z-0ee~ K4&_RswaF2c_<@)J literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/get_and_set-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/get_and_set-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..59821746a9a6ad433a371e42108dce3361496f87 GIT binary patch literal 335 zcmaLSF;BxV5Cz~4C{$ztsbXQN!U7VanGkZ9Kp|3wGL$l9IGvqKW5ux}+X408*KLHv z#QyHS_s*tYY_@qbg0UC9Uz2Z4RnFvjkzDS`1L_JK`G`gDd67JC8%tPyVof3LO((^M zYO6dMS}H1% zCnfp9pG0thT;NFr`%8j2n!rc&(eh{+ZCRRyULKlIRO+3B+L{hLaz$Wj5JvmpIpCzs rPnxFXq)4vrTG~I%zflcze|(a~VeR~%g&~xS>v7A6u^psC)+tURvbIB9Z>&$-9{`7 z?Dy__?`-}>7MnN233<``HTu>x^+KLk>E#YR7z+&wIw~KL=)J7ceA`;2%_kKY65jNZ zZ&08`&2dF}i?5V-sGHkA={zb+5)UI&k{fb8iEC=RaUdk{V~^U;Nn8xndRNcLMIofZ zDt%ItE&T}v7t|#^pHq)$ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/initialize_copy-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/initialize_copy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4cc28a362797c37b6dbda26be01d430a7562676d GIT binary patch literal 339 zcmaLSF;BxV5Cz~4C{(m##KMBY0t?N=aAgP-B4ucY5~d8+#kmlxjvd)oQ2F(^jaV4i z-_!Tr+4LRa?TeKFPv)>D?rc-V>byu|WfUva>YIeL!y$s`H7}CKvU7yZ8@3cGY~Eu#|BER18(g|*6jc+ooB3&vWLux+?xICx&v pr0rLlrq!fK=C_tRa(BmmHYToH^-81n=?}-1bRPf! literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/initialize_table-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/initialize_table-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3e14a19723378a30d16c4c789c8fd5a3a27108c1 GIT binary patch literal 435 zcmaKo&r8EF7=}GaHhN6x2!Ef`2rP& zj5m!G3#`zh7B~Y@;}paib$R(GKOt$#j$13=z@uU3yV^O}^`>PkY}hoYeV-jAEm-ez zV%Wv+pJ%YJve4FKa*&fOnr1&69qmTm(2bLNMSYFbh3V9yFt)^!N==8`3l~OvYt(Q= zCS=JDlS(SgqFW`4vG35h3v6TP(763(<6;ZPiyhs_7F|3}f&kC!U?kK!URl%Zba7L4 rRRPKI0+o4><2c{TqTbc@HkzCSne-ol;VBhoI{{C|HlSt-oQuBzr4p1D literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/internal_compute-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/internal_compute-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9645e9740a9fb4f0fc98a29e1cd8072da5e7dd61 GIT binary patch literal 347 zcmaKnu}i~16o)%VEY?Y?i%W?h3Su)kToIzxK!$dxb;@wOyS$hqm%DKHqV&J_+TbK~ zf4}#A-^uusO*d~=GWKG2E2P?%#Z;Z<@uf0^&Vc69wp~vcvFJU^O>f&q5bYsQ{B=xwX;BQAHccEwRz49>4Isy<0U~w~#7-|d5X0rrTxhvV><+Cu zzdo}ox zRuI?^iU&`5g#B)(zsXm~y1OfMcZ=+gr!y#oA67DXu-a({KQa2@5K|BS$^vHq%B3Orguk96Vw77j>Fj1F>arXwb2~lSe zVT5}RQKZ-}IFF{VX?3)b2~Kd<6ymEV@knvKk=eNa#(8d~-q4oY;^0<5iPyUe*HMi( z0!S8W;xti-gu17CP-4>Fynzp&&(5aspo+3TiUXFJ ad{*FpJ|$9gs(#vj3O+<9niEN9n12O`D3dGz literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/key%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f8c7a59bc9faa25229eccbac4cb57af2f096c3f6 GIT binary patch literal 314 zcmaLSy-&k15C!lK$dqQSSXfY4V4-GVxDEsgkusE_A5#X)b}qz}nzWaYR#iLx_P9wgp>$u)%?mhhjnFDDX literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/key_hash-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/key_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..903ac486a287e9ccfce8213a4a428d73b299564c GIT binary patch literal 323 zcmaLSF;BxV5Cz~4C{!(M6$=XrOIc_Z7_Lj85Gg|$N|`d8F3ts8aqP-=LH+l*jbLPd zPv3iI;}4i^UaSCkGKVz>X`5=M&dc<&;{!_aGJ)i^DAR|nbWF`VwH&j-_DXEHWyePF ziiG565*?f7_OG{0iUKZnPJK~e3)cg)CfDtE0MXp{Y{D3(`Ho!h)d(het2CGCqgM4I zoILaqT+qow_Y0ypidYZiy{nUDvV|; iMrAsg$GLaMc0P?KZ~i$JLxs2+PP|#ylU`}^KKlV#_-!Zv literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/merge_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/merge_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7cad86dd409b31ecaeb65fe500a57adf432f9190 GIT binary patch literal 348 zcmaLSu}i~16bA4P5{m&vC@wA~E(&5ZDO{ImHIShWwN4ox?=CORkxMSzU6lU!UJ?W+ z*N^w{d*8|YlPz|yS}^w99=GHwUE~XSnnf24nFB$G(gZAcOS9-{Um3#U155JPPB&8Q zs3b$Jpbd(OUQpE37B_#I>mW^8*!5gVq1p8$ZPC{jxVwuRs4ILMy%|2 z?|bhm{(|)QMiSt~{Or;9)HbQQuJYL6IfCfDuJXsax5(R1-eEZNG$?t*4lNpqJ1%>C z{`)4sZV@xdCgB8K5p(sNk&-&0%nQzBBO9S&XlEg!MZL3Qyj2 zl5a_nCCzD#yrF00E$RCDZ@?D%kzC%ibhuk++QS#Bfo_jMSsZpR{@EIiay}pTycye}S}Sxe{Q+e^cvJuY literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/replace_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/replace_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..33cdb5729f9fef607dd74d14ade07bb0c702a44d GIT binary patch literal 352 zcmaLSF;BxV5Cz~4C{$!Zs#sW}uu!R@nUHXoKp|3wGL$l9IGvpfvFg~7?NIgK<2GVo zVY}hoefKV=pKP{$HG;8cecX_5OJNnzOSsBO^hhn}%O4;^VgWpUo4^{$$*tGtnl z%Jfl5zVv4jTrih-Cc*xiAWkUoQGKvHT17jS<>4_8ZTM8`F9(e^9eCu5z%(F?_Q7+& zNtr{IW!0oillwg#7l~0de4`p@k!U)Mzjqj0*VIcruky>Fe~ZSKa*hLj~_{UD5%4sNFJJMK?I50I##LmL;66+QPc)HAp$lr~u9PezM%94Qu( zwdNzm{GY|-8DnD7R$h<|IRGtEp~%|QP}|SIly@DATo`0dG3jhfUSI-^`=XTAvnrq8 cKb)gQmd4%wGbkOE@_JhE?tI71*6hh7@Q@1MaocwN|`cP7w6JgP3`FHv?{+IHxUC2 ztoFV4-t!!eKKXe5VkGB}dN)H?n=&7(qb$61P&6p4`a)3|3V86EW?{Uj38DOe3Vp(v zwUTqJkWfo}23g}1$QA1H_D?zv(v+XIq&DEt@av&+2DIv0&V7HkM(sxYG--jH%>%=4 ze$TuE!IGe@gZMZPvM`;a>quJ$tTkICW-8{khV{j4e>U@HGgl*9stsyZqE&=ip*LJ z?4}aZXy>u4D6lcxD2nofEWEh$Pqg!&op$&8Ey=kz%l@(Hhf;Yp_;@q4hUU2eYol-T Cq?nKZ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/try_await_lock-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/AtomicReferenceCacheBackend/try_await_lock-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..587e3aa43c88b5cdf8bf985c64f7a82013f4fd77 GIT binary patch literal 354 zcmaLSF;BxV5Cz~4C{&bVF9V4nHZcUP>7VF45dsNP8a7wtU7k&T&Vi*aT~EP zu;07yy|d}3m~URK6yn(&*2Imiin%(^qbqg?z&$DkZRIWy!CRI`$+mHX)d$w(6Kq>0 zH&l}&BWZ=Qp%;`pGS%ImbP{Blxa^$zMkXt6MskgAH*`XHe`v|@RLs&29rwjVT%@(q zlt)iml}kRU(0g`?Cl%Z;3-ahfIl_;w43c0g;?#FzXna{^zIv#gZGo}W1hxig4STPL zlC<5&aa>ID==NR?&M)EdZV{?QXlz9f$A{_6uMhuO?2j^eJ??t9u0_4l*!S@du1|R{ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/%5b%5d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d651429738de8e54330418ed1982f1afb319b192 GIT binary patch literal 268 zcmXBOu};G<5P;zhC^hj~AtA&P7Fej~^I}wpl%Wg|CJR}%>oiuKIIO#Yf##_iZ1HJbcT}0PLjh%~RgdqOJi?vvO8@ zc(@vS8BX&AkimH{V?u!0BtwdP1tsgOGfnmAtlFjvDPlIadLdtf%47?K`N1a9=ZAJY zM$rX7h$NLW!goUZF=aLiWt{&bgz$prR&+FJx%LzxddpX|WSC;oROR!@oL`m|!)+cf T^-H?Gy9R&yFi5v^GDh+b8>Uel literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/cdesc-Cache.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/cdesc-Cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..a502e2e2523689b686a0e9428be0a639d19b4cda GIT binary patch literal 973 zcmah|%Wm5+5cHvtWIK`3xJ?d557q}XI#Y)VbzMLx(gKciD2RffC^{lci2_OG(Xa1P zb}AVu(BsZNW_LJz6WpQ8%@@TG`mS_EyF>HCCa|orw6=IAMp+boTmK~M&F04jhQlq(S2rSbQWD26`zGTwgyCtJ z`s}rSj?~9KNXVR=Zgm`BA5EJ!mx5u><${_&y3BuWhPJTL%5r9T;pU>VMvDh(xeK!B zTy!Tf{=$-+;rA}#<6rKqblFvLkdf^9a}Uir=z+@CwI1uHylU+8ryiK>xMgJ@&%2l? zO^j7~&>7rw3uW5_-$c{}f9m7lgnA5-Q{_ndwxZgURFa~tnt#AjQD>-Q^+nTKB6fu4 z1|GY|$42}f>@)2y8(eY#{?aDrPQN6?W2etMQ41@mgb`q)W+2l=qncKN+@0Bax+_hE z0no`qYIUmZ0?0+-np9&2n2waxl*?mx=g8yV07qK>WD&ZB2Zl-e4QW=gZ=f)}SFB(sc45B;{NS%RVE?l)QcA1iIaE zci;VYi*HyT-^l>H^_K(2hR)U6&IMngGL3BU!hn60f{wYs zHjLU?L-26(4$8OV0Fdyp!#*w`D+c9bsAjM%YU@z&M`!gmUSS!MyfqWN@tW<}3G#wE z8)cK;+WsfV+EXW^(heon(oi208>B`@zj-b=Yp1hnCiwj2bt;Q21z%pnrnWTqw`8B> LJLUFHg^>RN=_pYG literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/each_value-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/each_value-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1aec99fed79670a4df0856626e003fd7afb34bc2 GIT binary patch literal 261 zcmYk0F>k^!5Jnl0L1gHHx>OzNE_5lGk0ppUk_S2foibRqxinUtTx2^`{r7cX>2|04 z?tO1M|Agh?jSRrH``u$~=v*!BOz=BYrjZxr24ukAOTnK`jYoApsu}@y>59+)G8 zL9LClNyWDN3bOXp%BZwMNwqZ8#e@w~qobcZ7o1(jw`wBzZ1pmZMV8bTSKYLh=Kf~( MLB3UP=Tr#!ABPQ6xc~qF literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/empty%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/empty%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a4367890718dd6ae84ba808c7f6fb0cbc8901c15 GIT binary patch literal 246 zcmXZWv2MaJ5P)F@WDr?Vmx?7_+66oxLxX@w8R$@8%3#^%(pcEJ$aYlm_BGJ)bh_{U z@$?My?;UA?O?NwBZ0S8e=h$)~Ho{up%UPrSI(0E4F4Q-~~AoMVp?Q z?k9-GlM_)Yi-H=Vsf&pXLZPK!&Urnm^2z(h{j|tZ@9fc-#!|mLlfKA1X}4B}!2bYM CMou9B literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/fetch-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/fetch-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..06545c29cf43a456c5e2e1a096ffebacbef13654 GIT binary patch literal 278 zcmXBPv1-FG5C-53MK$&sy0itOE-948^M!&-T7x0U&?b`yAgonZO(VFbW?f7zpNO;at^ZAoK^UbFeC5hVG*t#{P|;#?|?C4JPYUi+)cTwvE?QeSONHslCdZaU>z z8+NMx$1!P5$2_k!G9#HVy$`HoHEQ#hWhITyc$o&PMM=|D2rp@al8@T6U#>??-_pZr dw|ky?@+3SIU!MrE5O?#@2V*;~x0*Yb{R7=rSVaH; literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/fetch_or_store-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/fetch_or_store-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9e52eb03e50337ce0cd76d52d6d0f0e1ed1bb96a GIT binary patch literal 296 zcmZ9H%}c{T6vTUw7@DKSiwGeiD2UDZ6(Ld$1lk_@amr!YY~Grso4l~QQTpF^)80G| z%=~8NCOp7w`$YoavpcQPHB^@~bz3BN5}jxm8D&HhFK@ie#r<{khD^)#Qgdt5GY<`4?*IS* literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/get-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/get-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..87d6da7d2de6fb00e3686c8461fd23c43cb06014 GIT binary patch literal 243 zcmXBOv2MaJ5P)F@6e6-B1}c_xX&3N(EUAD<8R*c4DT8I33$bu=k?jca_Bb$}PWRnE zjnA<7JCFkS=^iKa4PB~*o)u|)MIS+QEQ@qiHWtO@U(^V&7plR}ak-1~9Fl&JMk|7k zw{jBpHuM0299ryr3`y1t>s>X0c~)zKMY=XxZvD&TE}&aAnj0$vSpv(b)t)!uqwcPb z*OprDg*3>i=88HWSjQzAx--VANs-RKZus~fud^f%Whg@lQwHnoT!@8ZN4CSqzsGIH)9Ie~ zy{qL1Y)&su0X*BkBgNje%|>5W`AXZCei^XWy2|hB-V?U(*b%@1RZkD|de6!dvT>3| zD+jl;bVUC(jR1+A2C{JpSuvuIp;^GH=(M3Kzc*U$;zbo9u{(8Ew_dV6tAQ78&{6a$ zQ`^rVI`0M%Q5q7i6Uy0`*dQbs_rp1F7FE7}{6;g;)A_#0%JjgcXBta&GxvIPen4|D H7y|zXWeZQE literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/initialize_copy-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/initialize_copy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6d39cd44f3703ef75e94f097f01d7a392fecf012 GIT binary patch literal 270 zcmZ9GF;BxV6ofmVv}!v>T@Z_r5G>U5>k?Fm}@rVN(jzF-T-j_g-Z`SrN%#(2`* zec#pW1IoAOpaGuzaff8WzAf!ku+n-nB>NZ!Nvd-wL!TWz<=Z4Xbm50{-cAHt-Ul)mA5Qyf(Fis_E9Y42 P)y3;I#6h{OQz`L3_sm$K literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/key-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/key-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..bcb72be8a8d6d489a9090d84843cc99dc7a54923 GIT binary patch literal 274 zcmXBPF;BxV5Cz~4D43YBVgRv(1s3Z0vKSR2WheubDT8G@7h=_kBijM`?{V7s>ArjK zf_%aH*C%TwTUNFgoJMNVm^D7$UQLb1`|b}KAQ16 zh|aq~M5!za*9q;$nAji`TKCHsYqBP_&CS^2-*WFtLdvUVRpy+Ql-0%cAr?+9vK=A*JtmB&(>?co zO#Wg1_e&b!r+pkS)O0E5W?ZDx8$LV(w$F=nd9EGG%Sl!Uu#>vR)v(>NJcp#~l{K1R z`F0M{-TDq7qJ4vHm_U+s(gk0RV3t+JVv&AYqc&kcg^%h+ztC@|*p{7vXVjP=>iE*M zS1&3@jR;a%6jTXKZHTNF3N76^=jEtK$6xE$X_my=*-#kATrb{9M{)l Axc~qF literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/marshal_dump-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/marshal_dump-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fdd2fcc9443511f4b6518943425f38e1575bd482 GIT binary patch literal 258 zcmY+8F;BxV6ofk85;iR&LW3E@Gx{)dl_%B-^nQ z@QS=m!sKf^oTKOid67^$EvOfYhLo{UNbTr{bKcIHa{lyunN~%%US3UetkwFa^g+R+ J+dGVr{{bVBQ%e8< literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/marshal_load-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/marshal_load-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1bc489f510464c1cf2487b38d0a631b4d348cb13 GIT binary patch literal 262 zcmY+8F;BxV6ofkk`xwDMLFznKD?>fIH-z9f)*)>W~rJEz6zTeKQrCsY^5wB06OHDtpm z(I|rDjoAx#9tVJEj=i=ag{&Ne3%;4bylf5Xs(3^rH{ptMAJvVT&{roTSpzGnH-UHY zq_MxAw~l%qghb7$<%(>GtmjfAT^M7{tSVM(8iFC~^S9g@e950Ak~%+6UYW%g=GW}0 QSUuc259E4*I~3lte{$1PtpET3 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/populate_from-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/populate_from-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..05209d01748cec185633ca244a1175b3248e6955 GIT binary patch literal 265 zcmY+8F;BxV6oflerfQf_)djHx2D(tsuS=>zqzq+%cFJJAxDK}JBmuVl?_Nbsr+Q&-s{GE88!Sd8T2CDV_EuK;(?NTMr%!AZzz(HWkN;~M zR+ezqi>3(Twb-_ L$#-aX7DM2F^ZQnE literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/put_if_absent-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/put_if_absent-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9936e81ed6db806f4c9b188848a64c30d22dccf7 GIT binary patch literal 270 zcmY+iN0^6(VIQ1C%L)b#~9hsuM^40QJAeZ70T) zo__D$+4KwMAFoaUybSv_#m;TpxjApj%P~b^v_KhXhz!_U-IVv6&J%7wQ4_!lRY!OK zV@p=oP>e}hqa0kHN7Tlq8ic1&`w}hX=AA=Z>*7vc+^G6{6Zb{XD`{3 zZGcyNM`%`5x`cVhH>XZ~Rx) literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/raise_fetch_no_key-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/raise_fetch_no_key-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ccd5bd5dde220b251b33c6efe5b362910d53bfc2 GIT binary patch literal 271 zcmZwBu};G<5P;zh$gNt&3I@ay7P?T+*CnVBDMJ}bnKD=x_l&JNxyW`weS6$?WjyKb zzW-+O1@rA2Yk=4Ow4r2q-^|^(F75-mNXk&sR`sk7bP^!mtGZb1Y#`i!q9K4aYD-W5 z?5;#r!R-*-4<=%GxFQ=2hvNW{#bZZ(n!v0aFr?UwU|JgIsV*M9YnSO_sF;zZJ{vEg z6)Uj=S#sx+vbn(Z-%**sol4kxQf!pwKIOMjwdDC%O4*F+V*I=~pO&*6KfMI!vC?sl)h@Y($zF*J0kmS$R{b8l|QfF1H8U6+kRc{$4(0rpZixEZ%QmgkW4gR({w zte?(Ny6eybM09Ae3o}TvUb^6`2`sYOSS-?4Yt%N3sPIwU>IeGa6x*>9ct))WqKPj} z_v=ONs1-pfi-KyQsSAk^!5Jnj)g8+3xT~LRn3k(I%$C8RRQU*G-FlDeVj#FE8e35Oa`tNI?YsZsL z@4fG4bb#6W3rT=y_p?(`Q&Y{%u*~Ksw5GwR1ohF73qoVi4-D9AQD#qj?G-j3*eZZ6 zO06FM`QNajfNAf|DX|FVSJ@8z*Rcmk=3}Q^9Kj^-(Z^5?V4SzcsxrH`re4R3M}#C= z%d=)QO0-O~I{@X19yKDa$hs_d+b3Tx2^S-X1q)Je}^l z|7!68>%$8hfam^qPqF1wy|(iz&%V)(^dvyMmQ{XxY(3%W9UB7Jp=s&vf4>!F3E41e zXAQ&6#oD9)8V7&`j~(@K0a-DikD;EyvS_TML^`WCabi_S?#7(iN3X?J96=V`*{Is| z)b^i2HJ&>aQ9DxHD8qeBY*3mU|41q8S(UHur=*ATeUYW;OV literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/values-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Cache/values-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5bd278e2f9393ad43e62cbf9649114bef991f3b3 GIT binary patch literal 246 zcmXZWv2MaJ5P)HZ${?~L7Q~V+?NU4+OAu|O40LGel)*Zi3$bu=k?pkV+t)zH)9JqZ zA7)>$_;_Ulu>J%kL4bHGt9*TIJ>lsS8v@v)Y3cEQzZGQ(*)VEn z4a4eg9nfFK0U*I+M}3?@Rt)H4s3$Nl8tW*L&gxCPu_`2YW3KFr*J3MuHgt-ubODjip)Mlit~P==KgnkbjBn BPGtZ9 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Hash/cdesc-Hash.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Hash/cdesc-Hash.ri new file mode 100644 index 0000000000000000000000000000000000000000..d7f5a76a8cd642854a3f3764789e81316b171ad6 GIT binary patch literal 458 zcmZ{hJx{|h5QaM-C;enVP$ahe0LXk^A{8ovREB;`9xTUkh=pTEwgZ%3kCUo`1z9@j z&c5e;?|cy-;AZ=1IKZp14O1({oFi8<&Xe&ob2S3=w9b?3eQgCRcdQZsLmi_~K0U!` zZ{Y4k*)aRwwEzLxHA4Fsrdi9ZcLW(6#W*G-m}HeyB2Sh|77u;^Qy0khwm^XeX=WPf zX&nTmesi?4rlFn{N>Ec#ZnO_zM+>3MXNt!uo}^?H4kE$z?aQ_+jsUx(=Cw6iev7iF zp4IUw=Cl!|2R!P3|e>!!6-)SqUSa`}; z|K9Sz*FbWkrKf%9kmI+boi&8uRMVGo0+wpy1gL8i=~~No%!bbX2u`)-UUau-)kNOH`?S(UPxwb^i1@|{m-tA zxL`cP*No3mO}at%@`rIB?lOaH@|I082tITPyX5iJjaC<0@zNMn?n#KSd#8gh>V((K z%*!GOD0`WcV=vep70fsrb#=Ja3wu!~*cnZQ#Bu*riuBx7iDOHd&vPSU?!m=rjc#Dl zE=3Q9Bb^HuX9Q8GnT@AL=doj{#8^*bu9c%yHcnCM!tO zmRd@ZoIzr+kc?woFk$HIffK4fAME6e_rf~sohK;KHNK~mPFTqF5*KJ-qS30a9W1q( z!&DncJdTpQ+jK2&bpf8cYjU{7@U{{J~Mk`@!HMm4(Y!#)!^!sLzsbn*H zJ%Od~CDMWPP|j$1I-uF63cWTIpETDrHaW05A{`fELgl7a2j*gyIj{c)3KE}40=-mK zmyJGenrVw<`{U-#-DN<*6*31Dj`p{RT1Nqd~Z zGNb)K^vRWfPnmDabk$HwWcc}^sMP+ArqS_?!GLfjO=qN0;el&cf}{KJA&&{%DJDZd<>9wjv^Dr|L0}Eb2vD z!ERBeQgDA8>=XG8xx-0y+$)S&Fo*sy?tii#{q@suKRWamz3A6($wq7IfA7x*2epxZ zIC|yJd(E7*mZOcyY44stx}#S1Q`}ze*7MmK4j&EdBP;E}m|8Tp_~`LLj%HTRcI$ey zUJnmzpuPKaedkxl+8iEu*1|*jR(rqs8`0jUF?T`mmT0EU7WG7Dy}vunf1*3ur(Z(* R2k;^J^T)r>Ydt9?{sS%5Wj+7^ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/clear-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/clear-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9221be0b2e609cc9138ad49bffd9e8ebb95a4739 GIT binary patch literal 276 zcmZ9GJ5R$f6h=EBw`$girJIouU8v{VC8ZF_Ll|h7GFZ0b5UYMfwj;#9$0Zx{_c-Tn z^9kk0tCs*L_tU5}`o1gmn&PcAiU$Pft)}>~9fRWig%1j#3Hr?Cs9w0dD%U?O#UrX~ zD5hB$Ej{d(&xVKVJOO0DY?VtJD5{Bv6uT8{t3ew@@!n{0NPqtC~?Lsr3E`dTM4`HBT%3#^fNn^#A$aaMK_M}8C%;)m` zck3_6KHr=Kc(KiSNN2_=Vgku~Ny)D6J@WR_UUi+ zn3N@?<0Q0_4jz}k75Bq50?f!{(8e{S#mIdO%?dU}r!-Qs*Ge4XufW1g9E?{?-UucZ zjAoQc2$YWJPzd9$Kqvm5Zbzg-t;O-c5z Tejb!^yR?2dZ@4~b9zy;DCL~=c literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute_if_absent-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute_if_absent-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3b02d7f4deedebe8fc0547ffe56ebdaf74cda726 GIT binary patch literal 303 zcmZY4F>iw~5Cz~26^+7*vSg!6voxsVWuZ-r#6X9ZP7Ej89KpiI$Tq6-@9UJUnNRP1 z@9x&$kbJ%w0q`zOOJh6CC9VF&KixLaYbl46lU~+aL7rSpDfFoRhe!c2fFO9 a={&B>H2L>OI22;LZ2d4+Gj&qTx$GAmb7fHg literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute_if_present-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/compute_if_present-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2ca485f9c3326a04f709320e026b262937fbe10c GIT binary patch literal 305 zcmZwCF;BxV5Cz~4D6N_`Dg#?s=t3j0U6(*1Qid>;Fl9K|&V^X9LJ=!3cd3gj$Km zpvaNbzzXk768(~5#;+*4;GIZPSron#+K*`=qEKl4H)E{XaJqXK@VviV7g^0|{x5zR Rl=^0Eee=Odd$KY{_5%xIToV8Q literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/delete_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/delete_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..85241798af5eca578aa0a9030128d35efdf8cbfc GIT binary patch literal 298 zcmZ9{F;BxV5Cz~4$W&wjDPmzkVWCn*GhdfLA(DqMK$tREXXiq!IB{eP zLY){P7w5rAwr3@zneBBD?Yu`1pI$W1_9CD(By1y;9l}g_A<5Y9G)=1&Ppj e&`h*Bm1I%Lllb2w^C4H)%j8$Ugz=ZNFJH4(UA`zc+c{9Q?`~^{lyvrD6HHw(b6ju z9qIb&^7!VlqvO;4 fH>#0Vr;;=*^EmqV$8^ZV?L7IzSdD6@(7EInPYYq& literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/replace_if_exists-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/replace_if_exists-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0a4630b00dee00818f0be891d15b68a2c4233ac5 GIT binary patch literal 314 zcmZY4F;BxV5Cz~4C{$z(U06_9s8rF2@wx;Gkurn<(ka8qb}qzAxo>8_cKo zzIPYP14QpHMgTnNQ$fBpbrs3WJYHEE6cdE9LHd@?y8wdMERP?{))K2fSVI7Xm3t;y zdS;>{UElo=?Sd?Wa2UCg!obaJ70h9Db;N6)w-Gz|)){X{tAq|7l%l4_C1*Y_Qr kHn*CN_{G#n>vK^WmU$fgd1*RiVl~fxGqz`Hub6Ym54r7WasU7T literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/replace_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/MriCacheBackend/replace_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..32ee2e4fb5593b25c0543e3b80be1fac248f6824 GIT binary patch literal 315 zcmZ9{F;9d*5Cz~X3|^!%AvQJy8!tIM>bV9zC85AVv7*?_E`w}XcFFGI<^H{#RN754 zllRTLSbswF{$d2clRlN?JJZyWyeyJyOQS+TY(!}T2ww9dd8j%|*nD710Hu`&6dgUI z=t(zsfA04|o-1uLg&&ST?=V8 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/%5b%5d%3d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9985cf504bdfd976185aef4a698e7a05e84832b1 GIT binary patch literal 341 zcmZ|Ku}j1-7>D5-r1q|paJUE}by1MJ3{GDWs?|b=yFt$>NJ!JvhNekLQsw@86ANzc z`Q`cEllUFhug{tRJgVc4yG}QFEl#U6#vcz6L@#BPZVsK{w0WZ~2iR*>XvHRDxN-$$ z9e<*%=c>65gDfgbNXDs_f@!#zf8J5kPa}Y5ropdbNb->yXYm47c`GEZ(t9cDt^0L| z_0U#nMc5xiSdd6PQyWuz=>RC#gK(tt#|iamNo({#9IYiMx(#dRHA`wP^*2HYN7#og ziRCWLbr#3j5-+kYd5;y1e z?XS;O`~};OH^Tv5^m#9QXBxbf>pENG?+Bvzs?HvdofWkCq^$rr7+o68Cu@cFCFPxX zrMwrqxeNF6sHz|xC#EDfaI?I-r?#I)fPhRx7{!nlBemY)6(mI~m8i34CE3nj7~+Dn z(?%2i=MX+age}sOWkEUuD$F1~>B8TnJ~`4_GZ0Ui62!Fg+6T=MCY1R>2;m5atPME{ tKhI4b$N2`Y@}x-f6xCUB-;49Zd{m^N`u5+_Ig?*6aR*}us!BzjL%;O`YYYGY literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/_get-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/_get-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5f14a162815a2bb665b86f18ab4ccea585afa7af GIT binary patch literal 309 zcmZ|Ku};G<5P;zhD3q45VnJdE3tdPCrt1<2M9R<(kWLva$GJ3C9A9KRpuRm$BeAjH zf8X8J@(7#HcM<@v`n*TiQeAH3bspZZ6S@F`k0KAFqBY3tFWw-)fpkh*jK-jLDHkoi zanYf!A1}o&$TGMcjQr*f3GV0Rdv3aM0Pxb-`)&#AWZ=fxasjKPkqYzhMae317l~O< zMVd4de-smw#i|*5HdU|-3WyWxrDLr>PwJCpjiH`7UMXbMOttfxWfdy=iQ~9j26YKX4$^bCoJ?ZTt%Yyl3

    w+5y6p!E&4nvEuk5+bQb5$7v)s z_IvNUce4C~^~W0tfERt(qHC!x*YY$E&zMCQK=5AVVN|pRdHu;71lW;INsG}K)GpDxt&BPzY#ALB*#-2%>)(_5+p@+`&m6B5GHRx@^O|K9D*B1zxLoAn m<$Z^T$J;$uBR)(e$tugkn}2utlT2LAJ9cDxu2RLVjeh|Mdun_D literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/cdesc-NonConcurrentCacheBackend.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/cdesc-NonConcurrentCacheBackend.ri new file mode 100644 index 0000000000000000000000000000000000000000..7a32239a33aad6c294ee235c41a5e4bc3caab33c GIT binary patch literal 1000 zcmbW0J#X7E5QaSzl59Cn3KtIA0v$AVXgqYHP}Hc~02-14jWZDeK~X20HANB>m5=`V zlD2Fq0lE~L?%vZqFOR%e(Jh+&`mPv4*UD5>ECsD=JmpcAe7II}sU&NR0cn?%ZQvVa zTaZP7f*+Sz@^Q5>K#Ln%g8%(r#cAMb~6fZP2 zw#I=OI~u>(+bQQUbLJU(1J4X$ACv(TYp9E5nms)=gx*T|I-^pd{0FK zM@~BSQ%_HD?58>;&YbJG+7EfyI&Z^i(P$0D;iYxtH(YYdsc<0ovh-7@jJ%g4EKAYuo&%Y4HlCuIqmk)w_)e~g}zcn GBj7Lf&L?O9 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/clear-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/clear-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0e30f1682fa51d637205e297cbae92aa88d57568 GIT binary patch literal 307 zcmZ|KF;BxV5Cz~4D6N{c>QadzEU-`yOxGn4h?JonN|`cPXU8E{9baTSLi~FiBC)aG zyYIc5)dy_OuOtDU?e|fIj+%O-msPfwMxjd}c`K`oT{@?*dB;`(oX8er<>;KUp+MQG z7nE0Jo4Yx3NXin@VH8G7g5CW6i0(QL0FfH|m|H=b59org7qHG-ZB&W=nVSK>ZW zdrOwfKZ?uA;$p@gok$MJ1z1kK4!n!?wEgtFb=32K!YEGdlnznzTqr|djInxAWy|}A aDVnEo+3mk;;z=pDbNdsy9!+7;d-ekqNoMZ= literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/compute-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/compute-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..66f76da213da87ac7dcb41a81eff58c9dffb44d9 GIT binary patch literal 327 zcmZ|KF;BxV5QgCnC{zt&#e&2T7FcM6n66785Gg}DK$$XFwsRp?9A9KRLjCtR4X`m< z@~h{*v*ib@-(E-pJelJTeM@ze0@Xe}C_ zbJ^lEmmQk=<~Q0#MFH_J3auo;)hz6|?ZyEhaAP0JCB)glt#{P|R#~GomdT@5V&hL1 za{=2JGEDwqOimgTGk0%Aw2cmsX4EUs+HjyUpN=(_dgi&%$f%iWA2i1VYWhmkuJTt)yX`JTlcXE*u&kL;PA+>Eo%h$eVZGBEXSM zK}Js2hCsn(htFL0Xqub9^?h8Hkc^YiN)lWx)C0HuGy;SP(-3~FAjwB=y{jWw=dIFM zr4L$(o&TXS7qB}+hRI(nlQWlz1$=KsypK`O1@^d;PCsh?H`>XdKB7To;-+E&LD5zc#8mg z(m842jR}UFiw>W-=utP*v0!heN+?>52MgZ65P!HAGqzt0U%&wAHpTX*}$!L)dE&oqcoPulU8Eue<|jI zwKZgz{Ii&xFeYa0(TZpvogmGqSDv-uK4rcfYb^E5bD@z@Gu1w5jtSKCou+BED3jHF dhv$c>&f>7{_TNR}Ng+4$fFs$S>s)i^(jQ%AX%zqf literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/delete_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/delete_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ffebb3b9056919ee5d580ef252aa06ff6e69ad51 GIT binary patch literal 329 zcmZ|Ku}j1-6bA4cq#oX)aJUE}bx{zngE+ifs`UyT?gl-l4&fzzwV`QJl2p0>-qeD) zxWDiHzVB%M4$IdUBLJTCVN1R-Rk@VMMSNP3B2TPGX(Na>c@aPE8%tQdVNC!#qcfw$ zU@d8%p=jtCMN7K6{u^9Jc@B$y;7SSu7n8I_+YUWIV23WG=deh7wBD67I7w@%sE8kw znvQwoikPX#v=5qNoRs-W qlBAp!@!3sFhr6p!R0G|PPtrwLdin3VaFUDjX~)jk4ppYmx#SyH(r={z literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/dupped_backend-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/dupped_backend-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..41b16fae1e3371a06653d093f695e99738aaef62 GIT binary patch literal 326 zcmZ|Ky-&k15C!lKD6J?P6$=tWSYV+UShy~MK%@-q0AYVOL@*$+ zzjwcPM~hcjJwK8JxVN8M3@xd8rRP<8s)oKt#RQiJv?_t*sjSkwed~~`7v3Pij%-0z z4$h$s1(z*8OySEv-Az)KaMC;d&I1yhPvDlj!_Wgnedywa1uXNPyWr~?9OsQTSf#f{ zi*@)mnUCn&l4bH2WpY%1Hr_aqY?3`>IdwX)HV)PH&9lZ)#{w4y88u@&M9njShCZ?^ ht7la@zq%f)`7-`^@$X+TQp&Sw{f=D6O<}nA*%w-JZo&Wn literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/each_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/each_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c892523bc390baabbe7cdc522d922853c2356673 GIT binary patch literal 325 zcmZ|Ku}j1-6bA4cq<30yI$Q*ix+sX(!Rg&ntrj}m4SG%;LXy7P&@`_ksp5ZcYC$Kr zH+&zz_Z_X?VEyt$65zpn?a;SWS8KH_lT+lfWdm0>g6O#@llwz!k=L)hL4ZA(oQxc; zMdS03#78bWH1*YAZ5tH@#KS1Gk_6|ovg5WJ2Y^71edw+r&IWG1s}^vQHA-WUv=STt zqcIn_jUmJ2FUREMF)@R8Rz%zA0BJ_O@~jOnD)a7GW2tAJ3yqALsqKU2m_SXRX<8=7 m-Rt literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/get_and_set-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/get_and_set-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f5aecd210ef91c0de41eba1358bf29db3a58d38b GIT binary patch literal 329 zcmZ|Ku}j1-6bA4cq#kxrI9vpgx+sX(K^)#K)oP)`-Js{xAtdSRH8jmTl2p0>-qeD) zxWDiHzVB%M0gJa6k^oQUutwifT`kmcnVjy>Gj3|;&_@ux7G?6dZ7uTpoi_-uA(NAl zgSBXU&Si_wTy|*c>%YNOR1^^J2ceZDxR|6hx81M@2<*^@^c>=B&#iaW3{J8}X)Kcm zt;Ev*c+3TGX~;173o<#1Oibjx711i%LYh&pJZnQqWp<7=mU`y7(8#D6(>`d93DoqJ qrfD@Rle3!+4|i9eTn~6VKFQ*+^zz?z;iQn~(~b?@C literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/get_or_default-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/get_or_default-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..336ad625ea5621630c5201f7e1e29fefc630b61d GIT binary patch literal 343 zcmZ|Kze~eF6bJAQ5{nrvf(RmUQ4pKK#n&Yo8_3WOTBi)h-Q}e@a=8olL+O9-#fXF8 z{=VPO`yS2TVe$H+Ilz-TY|yp3t`_3BOiuUch&H6ghI;8Dh}K1!JnmY9w0@%v0&KO) zwc_3wR4%8y#b?SpRQ2_r>?$e>hzHN4;2JI_Z$nMz2Y`V4J`~I$&IW3nt!8kNH9}&U zJV?Qo?wcewm`kM<;lC!~BTCq$-WwLJq8+4}?u8?5_*1C8C5_QNag<3Ux*5|hXqGUP v`ZG<_YE~xaHys}Cu70+X4=O$0j%8UKMqmCrG@KOtY}&Kcrl&HO)Y|k5Rzh`y literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/initialize_copy-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/initialize_copy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..27eaa11bebfa90d076128ea752f848942eb03615 GIT binary patch literal 333 zcmZ|KF;BxV5Cz~4$W*jr#Dc^S7FcKort1<2M9R<(5T*>4<6MYU#~0ZSsQh}IMl49| z_wIY|Z21n+>oZA!M|0ev@2IIFbza1gGRiBV)i-iU!;t}d$%`1u&Z21EM2i4>G8q{; zT8qYKLU#Bh%UdFg0>N literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/key%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/key%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4284d5b23d5392919c77de92ffa2da91808b2fee GIT binary patch literal 308 zcmZ{fF;BxV5Jo#7Q<}A6L1G9CEW`uTbs!Lkl%XAS?Py)Qz(_V!Rn|iA+tMsZ@r)L7>y{yvg*g3_UPu?nk1KI+uoSaiO6kK-d zmCIh)=I%`FNLfNMPQqx3aI^g0bJtHJKom_w#MY4HBX_~qE7;_%HmXXWj22lqi c^I@j*B(~lD+Y?VpdA$T2&<)%ahI>zc0Y8;zI{*Lx literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/merge_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/merge_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..182eff7b929de628ead3e8c20f6c4c06715e0180 GIT binary patch literal 345 zcmZ|Ku}j1-6bA4cq#kw<;cyW|>Y^ZC2VLGR)p~^vcY~f&hmfYP*U&VtB&l-$z3COi z#q}fK`{g^Cf5PJZjRe4pK5Wo6R22((nn&jynmw|fOA|n_&hqGa*BIp02d@!eOFAVj z24hgWl#2#mxoA;Ww|{!8Aj=@^hf+yFa5Xs_ZrY&-@aWL_@*KjX=f>G$24_hv73R^C zlI7AJIcB}L)TEjC^_UnzR!-uhDT7t8gE*m1I@b6zQ@oBF)1#K?Ot3AW9zIY@nS|_t9U;SLhzo^vuq(Q>OsYv4h4yq z|IU0-QQbu~nBwxufqgvu`R(dv*X%wEP|m?j27h*%fO^OVK|7Ta_%UUm0i((Y6wW_& zJG+C>fyVIX!d^v5|YSS^9N@i_*1hxWpbN~PV literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/replace_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/replace_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ecceeedd7a9fd960bd6110bd02120241d7f804f6 GIT binary patch literal 346 zcmZ|Ku}i~16bA4P5{sFH;vz_hi$bv(1mSgwRs$K@LF<&^xVyZVBbR&Oa5er!WHI>Ceo#*kT#ZGgHtmDcC5WHo1{Istv^74aM2(Tlw zAtMKC(YOtlHNJ4!peb+vB-cTfLD&sKD@kxYSzB(Kp#$*n(E9is!nEVo^~DS>(n@K} z<43K;%Kd<>_u|TsVe(gGawM6U%m*uib+CsdrB*ps`!ALG>RDx}WsVDtjH)s1yw)>; znhr^l6tg^z?ixHUBhn@N=6b+oWbiPJ_v6hp^v!SnZR=Muc{SDAk!`u&Xx{h930`J) AH~;_u literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/size-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/size-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9498bd6eefc2c2abdbe709615fbee34ed3f2b157 GIT binary patch literal 305 zcmZ|KF;BxV5Cz~4$Sq{8x*#!x1s39=({%|1B4ucYQl<=+?Ks4$@`1bH>jm88tv0Gkw?>OBTp;G7 zlv%V){z*(u6ce-c#%2m3!@meQ#wS=GocKAQA+DYl`bD1 ar)ZwUVR!$Ii6^Dp%y8(=2@6)&_a`$twid zkWNU8-Wb#_;iAS@E*jM3?Y|4FAWdQ38M)&Q39d%?nwzHY0K7@x`kg7v;*J|<^9h{A zl~kC8Pf8X`_e*BhqnDbr_xnRLF|b)N!XHf$tb#2>F}2dM+UrXFZCPcgWsVmL8CAo# x^EAr}RJ4zxD4%5E`CWsDhZ~LiG5UTOif6w2`e>^^NyWw3vLVxQl_+j)^aJL|dA9%n literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/value%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/NonConcurrentCacheBackend/value%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..79976a36b977ea0dd3bdea8b0c5d5e66652712e6 GIT binary patch literal 314 zcmZ{fy-&k15Jx+pP?3%m3lc+E=+YXA={gVyM9R<(P^Ju)?Ks4$C8R^(S_y=!>Hm(|V;BIUEc6kaLz)lFdRNcjB5#$JRd%lx-}sY? zy6D;%G*tY#s2F9GPqww?$u>Cv$+1_Sc5$CFAC9&bd+Hh2l43j3KH41RQsWmPq@GpT e;`X$3HS&2H`>y|OiYKMGoD%kEd!`G`oFhLEr)j+a literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/%5b%5d%3d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/%5b%5d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9ded1703b3a21632c08bc962cc7ee86a9911d396 GIT binary patch literal 309 zcmZ|Ku}j1-6vy!!q!v3J94;bATolwRj!%T@d4&#lgIA{_AxU3tXquEHRq9`FYZn*y z$M5sLN8uZ+USEs=c+$fTeQnBOC66-_7VnP%1lu$tw|Q-ml?PTKz+up$wnocuEH_Nl z_{>Cuy1bn3AA&T6sO!0s!ob-)ykoZMJAhH?Thu;;DCwB>u2{fHQb~mwxmS{}{Vzk^ z=&aozhKk9de1`5UADtZH#I(}Wdi+f44@WC&TIv~BNKHkB(SEcX<*3Y89LL2XBg?A> ihntH}rh2@dMv^Gc$oYRsQ;s;DBlgC&Ol=f%F8%>E=w~DV literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/%5b%5d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8673b62a35053b2924f62f5664142c04edfb2cf8 GIT binary patch literal 443 zcmZ{gK~KUk7=}HViI8|AUeu(S7flcrkL5B%F*`sEU_30Q>AG*MS=VoAyD0v83taHv zt%vV@`#kSy=biSK&nPIJ=b;In81NZK zxKj89IdMpYe-rTh1bxg5J^Pw=<3cJ(!bc^uk=si%>#aw}txW8!S$5DKnrt79VyvZO zrQb>Fjb(+wnmL{+U|2AL+Id{dGVlaZ6s0Fg*uAS@d%sJ^7waUv`ES|Xtm5)8)B;V- J)l_k7qhHdCl@9;_ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/cdesc-SynchronizedCacheBackend.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/cdesc-SynchronizedCacheBackend.ri new file mode 100644 index 0000000000000000000000000000000000000000..6c503249e58241d76ea978f8316bac8a30ab1b5e GIT binary patch literal 921 zcmbVLJ#X7E5cN<<@<*H$L7k!KqOBboqa%f)Lfr=N;0#SN5dlF_Cz~)u3M7>#{q;Ti zqmm1BDLCET@?1R=M^)?6(VcaC1lWSPFZd(mQJjh4TlTyU|0uUu?F zml27+-z?Mj_ZthmyyF!R@=t6QA@oBZdTaE;Xwg~=+Mnv#a{bITSQrOPv*I)rDq!) zKkXqw2uyz|G- XLs33mrsv&v2sGlV{{vU1Y!&zFu_J)v*~s2mqrR!#q3r1e z<%vvtHz&5NEFl>up_R07Gnentou&~WO4C3ltRN{ybip?ZSQnkrRHaW^i7fm=+(#+% ze;_U|5*IV|=mguc8uG#pD)2sTQ|8n2&e?$n6q>m0xU?oj%X2~6e&u=IEUI*Q|8R*G ZNnNG4|Gg3~N_jm`f46Qxz0>G@{sVY)Wsm>> literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7d123028c0701291d4ca186843a8971432f55bcb GIT binary patch literal 310 zcmZ|KF;BxV6a?T7C{zt&#e!JE0t*d{uS=j1DMJ}(m@-(l^FpjRev$16gW9%|1kr0=BoAe4k=F;_Ai!ZVvbAK?H`Y5Y zTYToSLsQ@UcD7NTLp+Q^D@kxQ1AA_}aR3O~*rV}Fh_iuP@2Ul?vPNkvl1Ht?#-AwW zg0*pfC?<~<6Ek*iMYN4dNHgk{XKh%g%%@|GrJi{%G%{+KB;$kSm_SWmX_{7xB3a#b eINcrFSzH#$^?!dtBA1u*`ZuyY*E`LfOMd|Hx@gP* literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute_if_absent-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute_if_absent-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..77a812e58bc127735da66a3b44bd7af9178e9c22 GIT binary patch literal 330 zcmZ|KF;BxV5QgCnC{)c_bwMm)frUnlmnBe$l%WhXOc_qLb0Jn7JF*?2@au8Of`r)b z)AQcN`W?1!&qe?|>iI~%Gflmfmu0dOW*8?=C|hLQk@gWpFGZPTRcDDcC)N_cY1X2% zM$0d14or0P#6(ZJx%s=!qN0F!oVb$0z}12tneC?$AQVhPFxC*~BeUMsE7;_%R8%Gp zO7gw`LD2e; jy(*K~ZmEAYc3|qDm~-hj#=vm& literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute_if_present-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/compute_if_present-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fde9878ebf53faccad06ed3051759b97f1bced9f GIT binary patch literal 332 zcmZ|KF;BxV5QgCnC{)c_!GKu80t<~8uMB}gqzq-CVaj0H&V^WUe39)4g3@h}RlB*E3p?z!#80U$JteL$8FX9Kt1RSQ^UjnY^o z4_b+hKdH1Lx-5u9iTo%dof3Jm$TwcueZ)AI}cbYqw{s0CPasB`R literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/delete-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/delete-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..53cea6381d88a3f44263d39cc0d42bf905c87d80 GIT binary patch literal 308 zcmZ|KF;BxV5Cz~4D6N{c>VjCp0t>YmuS=j1$wL|1FlDf8=Yp*`c4Rw3;n$NA1{U^v z?|XN(dWX&F#YuoCJ03AAS63Uoq*+>{!H5YYuLaFWsXX%f%o_wak5(%0tp39Kz@@@x zE?czq?QdkC6a}RHAdHp{uIKtA_wCRFOxDn$jVnm=p8FW81+4Q%8>HEz(P9^WBo-!W z7yd|0UMMDJ>%og;pOipy*XhXAG)~)(z#8v57P&CUT*IWZak2svXxt|uq*~Byeb?f6 ce@W+QNwb^(-kB~6xt-U)Ip1+}FgyhE4Y{9Zwg3PC literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/delete_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/delete_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..57a36f5cff1692df4b1f271618a6597c7379164a GIT binary patch literal 325 zcmZ|Ku}i~16bA4P5{p?Bii-#m7X`6FaCu##)j)=JXycUOcz1a*M=p2a?xMuM-qb8z z+`sqz-gh$pfW_|32!IzoY{=K9EEe)Ki_S|@HbiXgn1TS|2J(+q~dZKu{E|uwN~g{{0o`NZbkqA literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/dupped_backend-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/dupped_backend-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c3cd10e048b4e12383ca9bded5812dfb276523ce GIT binary patch literal 322 zcmZ|KF;BxV6a?T7D6J?P6$@f93oJBZLa$4p5Gg|$XqYlsj{SnII<{pypz`Z+iI5Ny z`<=eKquDDgULGw6xHtO^MrlQ}P}7Q>iorP)v}JsUMr4pZl@+VtV4k9-f-!y zQJ*N*j7xkNvzLFWtE?>H#Ci43B3d{fy$$ob!2u+E=+VR(%nQeS49x_Ni%w~*$gNiG zGJcaZBy$;lk(3|IpMf{N%~n|rd0~4MsZ1-Cc?-1jwx^M`8ma9lwt?!v$YZgNO1)y4OV*mgE literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/get_and_set-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/get_and_set-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b182ad0d661eee56521513ff0e67806e13e2ca8b GIT binary patch literal 325 zcmZ|Ku}i~16bA4P5{p?Bii-#m7X`6FaCu##wSf$EuyM+8yt}+KM=p2a?xMuM-qb8z z+`sqz-gh$pgvH035dbfG*pjbJSuEsf7M<_OGt?z>Xdm>a#NJK~r)c#KcrqvgRW$RSQlD?O{n52fBaR$0?Bk6aNm6%$7L(Q=HFGT(6= p7qcw7xNB&5xcNfW)BT|&3G*zv{%_itNX6we;@#L5)mou*@h_L6ZbSe8 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/get_or_default-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/get_or_default-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..281a63e2219b7332c82ad06d9904d14f8ac0d2a0 GIT binary patch literal 339 zcmZ|Ku}Z{15P;z;Bp#;p5JUutje>Z=O6HpAX&}W}c(F<`>~1EPC7a!_yHVoPn==+7 z*w4&2|H1qX7Ozi606genL%ud;v5<#Zbi5;v#$rho>y-~6cuuqEKCdmYa?2_L*bZ9M z)@b=j<(i3_9+_xJmzRH5S3#OW*!5gVVc=}yHq17C2Qb=wOWMyNOgd)0D`s$%R8mnE z-6_eJ{#!&hl1ukXM6oB4Pv))V!79ihPE0F3*5i{>?;KXvwCEXEgr-7av>z>poRs;9 tp-9oDMJ}(m@-(lbHP>|JF*?2@au7#g@ygz z``%qFKVkjxY6ZZvnGP7FZR)kUEXh@e(^CS;TTzltB^|Qn$XWzAPDV&)jrzf6&xFJm zCOS0D-8ryJiUQJM?&Hdb bQ#wzplHC6HOuQ(>^}PPwx}NF1X5MGNqUvSb literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/merge_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/merge_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a0429554bc759c35b219fad6b630eec385eb2303 GIT binary patch literal 323 zcmZ|Ku}i~16bA4P5{nr`C@vyMTol9xae7^%wSf$EuyM+8yt}+KM=p2a?xMuM-qb8z z+`sqz-gh$pgvH035dbfG*pjbJSuEsf7M-_b_ryAsHh^H0X3=wATf%aO6#?u9Eoy7D z{GoD|4@)4q?)v^{$w~SyD+wS@fhN zU;00dxshACBaMjz$N1zuS{|%|9OA^Z(zAMeQ0l#7l{GE%$Q3bDF=4bHEyp-1^Bu== pG0UQhyM~5`n=e#7-5*MlFwdgv|CWu3R9sFY-i>Whtra>K{{p0WZGHd% literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/replace_if_exists-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/replace_if_exists-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..23ad4b5fa36985a6e69e4776afbdb17c79156ecd GIT binary patch literal 341 zcmZ|KF;BxV5Cz~4C{%PUT@Vrq3rL7YjF%-)h?JoWG)x&zwsRp?96PcdO8E6n$%2H~ z@7?#_$^0FbZ_h>mJnCUfzBXmCl&4v^veYRi2xW!zC7pKx1TSe8#(8atl{;1uz;4i@ zwnocuDmP5j^u$C%y1f3Ij)OFXMb~pBg@KC+-7?$s9l+S2Z%O+(ERv2{?}{0mC6!c^ zg%3*dwf{lUjq2L{LQx!5uc@PIVM2Tso$9n83^@qdCnif6diqKRjjP|4Dkdrd| uD2j?%7M|ZUG~8Wj+T$lvJ>4E3C5t=@FaH}kUZi3*4S6-TWoo0CbI}3a{&f`q literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/replace_pair-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/replace_pair-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d39119310cd76645109352c3524c0109694c579e GIT binary patch literal 342 zcmZ|KF;BxV5Cz~4C{$!Zs#p+G6&8>x8Zj_jmp~y>hBDAFWw6f9g;;Uy$abj0uO}r7 z3~V>tz3<-1{2dl=&qe?|>S0H|Hf6Dpr&)AvsZ%J3btr8B!AqJ&4|#0~%RN>EuphLj zt8 zaU2)3ELz?)G_00JmFyE$PphS-!!+I=Gm|jSqO1R^jvJ}Cm^!^0+oIYkbT0k|hNpDd literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/size-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/SynchronizedCacheBackend/size-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c21a0d87ff057840812d5e979a18725c8f2bd731 GIT binary patch literal 301 zcmZ|KF;BxV5Cz~4$Sq{8SP+X@U}-JJ>k=qL^3V=6Oc^ZOaj;d#j%-J${CeDGVPU>| z_r1GXe8TeM%}an6ciO3>ecLR}oZ{Yp#DID^iw_^@FrVdAOYFHzMqY9$>VF4qci=_v6y zQp@;9;_5(gIazl>k`<|d7QQoy>v5cMACb4gcRUGck^7b_@6u>RF46igN@+b~`T5Op d=j|b1WEIP={(ES=DAmQZ|J8?1*tHcg(jRGXXkGvS literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/add-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/add-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..0a957cbeea459a6a2de1cf943f98233d0215dc38 GIT binary patch literal 311 zcmY+9F;BxV5Jnl039ZCbF#to9F0eG2uS*aRDMJyW?Ucc~#Fxavi6h%7@b7WbiT&Mo z?_CB*Sbe_g3gEf_-H~gxC|2?+j{+2e0ej2xC_J==Q0%cLfTNSj!$Oc*Pso;K87zmf zRI<`=f8N@m`5FfRKRkBSy8xEyfX3N^X?Xb0e4xR`;Lx(|b;0uJ&Tre$wG=k;M16Qd zHPXiaIlv;VrJ_8Flq_R6OL6P1;?YaR-iFM^lrx&7x|5E#-dpyK<+afrcUUUoy5^Pc qo!7FwB&ENTBq=U@@#D|aberDz=EYn%)m67=-*;^~R4)pxP5uBlU1F#J literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/cdesc-Adder.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/cdesc-Adder.ri new file mode 100644 index 0000000000000000000000000000000000000000..8ee6e3e8714c89fb965db63e763d5f1d5e1c6311 GIT binary patch literal 1626 zcmah~!EPHj5LJOfR%ORU8?-$%2SPctg`JfG6h^Q@Q8{r63$U9aw$XzQ0>vHeGT9{; zL#`C%)KBjtcZJyLp%5g9JHy8}?+s_a9NeYfzrC<3P5-o9$?{bxom)KCgZXH9o@K=S zwEy~#`RK`Q!6dUAxu!I|^SVsaHazVkdVJ$q*OZ<8+Mo7sZTe#ic`f;UQ>Q8Ln~IDd zq=&OwvUiKVogNIPgT>IMPafv}C0XVy>!OeF!F;67#oK1J6SZY8>{|GO#D#5gaYgbc zC*C=Jes)I5l{Hx;BvhzCY>1tlmOyfGv!i^?*Ijbt4P zbC5-P;cZUP2SL>4@fFgbX6>~s%boa0Y`cOlTvH|D?}ChI>P&hd{9IwL&BTe!vXftg z1iZ4wlgTI(Qn7`qJ~n|n?ND9^GaN-#>I7-NVH3^*frc5mD9pneWh;n$pAB_Hp58ybEnS;DLWDwtxU+9N4Ugud%iBV` zu2Jx(aZTh{Gp&hZqkygh0$S$e+*=e8cp*pz6>NiSZR5BuMQ}T#3bsan zL?RCA2nEmBmWdE|aE?U@BU+0)J45nml*VsuD*}iVasw-Mg^R)+)TJtL7nLV&c_iXx z<3$ru3!N7a@aRJg;wTR~;C2=@QgK^bQkVXL-cIL6uhAIBqbmax@u>*?3(EtLacJ>% z7ZI+O5WPkE2IWD~I<`-Eln!TWUDA9sD)nmIny_@3QsV|gYK&ecPIwhlCo?$dmj&h+ z6n4us+iK~9-%Gn*w$1L{az)T=GCiD3k0y&={2YWyG>nraAT2PN(!+L=AbyY@*KB>P zKQ51I)*D=^u$Ye?X#+FSIQy;BM~h(y48RW0FhBpFe8@k}NHK*$8g|WI#An+4=h=`6 zm-1820E+Eb)8jyD`Za!gi~ikyQojl}{ew@_o6vsNEC#wa>1K4VlcGO+Iv;&^``LRS P0IMJFze28U)|B)wkWCX) literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/decrement-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/decrement-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2fed5b692078cb1e70acf350ed9fdbcdfd4e5e01 GIT binary patch literal 263 zcmYL@Jx{|h6h%8Aw`wG&iiOQc2o~b`bqN9@Wheu*QwGZ)FT}#hi)=@Te~;4+j90q% z+;g=#!S3Ug48ZgFd%)C_ZFg?n@N0`E;DBRdz~1VH-yi#c%6_U20Zz&JJh2wT-G6b< z>Kck^*4`O{+Y9%g!uLD@9ZJ?+o6;fw Lg+cijuVNH`m3&m^ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/increment-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/increment-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a0276a14db8f63cb52eda532d0a13705bbbef704 GIT binary patch literal 263 zcmYL@F;BxV6ofkw Lg;BW|r(zU;to&62 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/reset-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Adder/reset-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..983b86fab9a0a633bda54bcb99ca83471480988d GIT binary patch literal 255 zcmXBOF>iw~5Cz~2l@q}lW$8wjbSa)M3sqYrhGb}yiNUhrC{_)J>_b)leVj0!^zM7_ zX>)(M*4Wz}SJ%@S)Nzqw{(RJ43{IFGscs@rv*LV8O8*vb4kOd8v zRUhl^_#0H`X;7?})jH{leZT^~}x-xa&;3 zo**~HcB{_E+*r9?OnCh$U?Z$^xq_64b{|1m!?;vwQ_i<=MoWnF%I zGMr;bz}A4yF$y2VX$6wQK%BRxgBSGKfJ@LkJnkC60Fq@Vd}JD&h7@p2mRLa@UPvQ5 z3gE&li)}JN8=xLEg*THU|1OUmvPmbWG%2GNj0|O#vgfbRX8xD?Mq!J5ilJ!Yz^irM z%${<>l(sc496+Pj*^6QagF9G;KrE{h_re8DaiqzzTTQXla?^`YU6$UpYo7aPk`%Je z(#IO7I##irq18t2=f+B9VwIXc($Fxr-Za!Vaxcq|rlvKXUaP9wzpKl$&tE3$=0e(D V&fUs$t3Mu_dZ0L<|L!rR>MzGTx*Y%j literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cdesc-CheapLockable.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cdesc-CheapLockable.ri new file mode 100644 index 0000000000000000000000000000000000000000..c579fd7949b57ba6680a0add35ec27b1f6431f22 GIT binary patch literal 1185 zcmb7EO>5gg5Y3^;N*pKsNWbU@i`qboOQQ1%TDNHff~15d&P4~YlE(4k)vnlG*>Ow% zduJtuU?-Q_U?aVmH}huS>;r#Hpa1%G`vKk}1J zMPIMRo-xg?G^?f_!d@KMGp**l07DqbT}NOnsgyAsyCNS-#-&&iE{O$Q8lonogi`4x zsSUe=k7RgSTeu#Q1-DaTr$B~BN*3I5B`=xgPTP=VwJZb_NORyt-o>4!z6mC0CtSjY ziZ;8(`eRpsw()C%FF|L_^0J2-_TpfW3uX-Yy5)l7;0?h-xu^>uE5qwxuls*VNC6X4 zs1&Y6ZTK9-vV-;sewt~dW-0TjR+9e)@`o%rh=Tm>!uo`OEY@h>wzLbzZ8}jpHL3(V z~gB+ZqyXk(LRAk-p^24S=lCL7JSm-OOb zt2t=Ll=w-H_NzJ*JV(4ocPgzc`#8iySVQy_*7lh}udcqX*PFG^{>DAVQ5 c?R1*2W2=il9pbotX-u75-y?gI|2ZIG2&Ym%+^s(8*pernrA@4{2d0qi)Q?+UGN@Bym!K2E$jkW^!d(N^QESq0s|+JZ+iOD)EqB z?Q7ndWJ}4~%9|V}UgVpYt$4E}MghT+=nBZpWW3=<-4K>>!S#k{B*K;=9cKiyPslZ~ zMGKJ1jaY}g*gCNT=>~tBV67!1vC**p^{J6J@#gesT5{mzvK+?7Vi@o4 zc8LzdNM>74FvXhd)a|#0Ra#1{Q|%NfmT8WSwx_E!1A$*b5cxglN_vsszrAzM>8WLY Wwnx~0hxx@0&>PB{i5LqbAou|?6Pro^ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cheap_wait-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/CheapLockable/cheap_wait-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8d0cfcf846e08599a25640a54ddf0e4898987b6f GIT binary patch literal 292 zcmY+$xVP1_H)H@2V8bW-~F%Z8Bjq@$lcfF&5em z^X7YVvf9Ju?THM)L-&;Debd*vSi!55++)mMC Y9Ui*)S3itXb2%4%CEse7Q#Cr2-`Ut;g#Z8m literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri new file mode 100644 index 0000000000000000000000000000000000000000..3d59d835cb8321cbca2ae29f0aa8006c0f26f667 GIT binary patch literal 633 zcmb7?y>Htv5XC(dlwv0t(vP6crlDi4`M3y38$d&nqOrShASn416QxOkJVkE)`jB>v z7HOA&6Zww!d-upU`4T?-`084K8|OF5TpAUEc&qcec=z3n=x@8l=oUk7kOBL4RTrNZ zYmaJmr#b{!k~RP@3ptB*XFr`$QO5mc&K3?X_NZ&+e+@lA<5|vg zF@b5-#k+MeH@cbA4k<%q&WG4@-Y09)b&^IWDY^UN8x|Q*R&Jw7uA@b5?}O~T+elK4 z!BpNlOA#1kgT{>|KPvgO6qDV`L{=BmHU*G6iCknb>xahZRuPay=;zPxTxkt4{0U S{majhxb6AhKkVAA27^z>)Wx;{ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/hash_to_index-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/hash_to_index-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4d6b5d6c75578ed4c5aa06be6b4f3082b8e5b5b6 GIT binary patch literal 308 zcmZ9{u}_3B6bA4c3|?e2#KjF4U8IB4y9J|?Fq|6YCWfYkB8`Pd+Sj1}y{$Lt{N9(} z_nmAHki9)(2XH@s?-h;Mx0ybz^Yc--krQ$~_v$NwP(bz#c{LL#1zC5R6xLji$1Ww4yoAr?-~vd@a(*JIPI>*>9F z-n+;TP<}k&0PwK<>=jLT>`J|Dt9(&w2H7)jt6M%fC6AwSQ~(Fk2H+i6<=#fVA`jNY zaZ2B3FB}RRdZPz~tJB%Nbl<@OL?g^s_QX)-x~P zduN*?M6VCj0Nk0c19C^FDpKnr-WmL4p^R|q8wJZ+V*tTpUc|R$XHlNsWQzbtRvO@i zCbZ9OIZ-(d8ZZCJ?t?ssa2RW?8iI?(JV^U74gkKu*rVYMgxMf1yJ`jJS*tV_aiUe7 z@GmKxHR=h+k@l literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/volatile_get_by_hash-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/PowerOfTwoTuple/volatile_get_by_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5ea4e3bcbd2380b3c3953a7c78987a49c1f1b33d GIT binary patch literal 322 zcmZvXF;9d*5Js;s+(lYqaW`p)-(vW7w%5FuW1BeiK*8EZ6M4?>B!eBxXxQPDC5K$ zmC!F#c%~*3Lz8h~3Ty?~7O+*c(I2FxRDTdwLu36kE)g@b4m-e!XZCk&ukw-^itJn(ey^J-6xX*U>lYI z-f0%*O*S(%e$wLR-|Hf(Du^e~wdx42j@%71-+lrJ5`GY)TSHt<%sAVw;H;FvpiVQb zc;e)EqtOMBMJ_bW qd7ihcIz7K#0`IT)OnY&+d@19Qn*0e1gQ~kYn!l16n10gC+WZG%y>LeW literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/Cell/cas_computed-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/Cell/cas_computed-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1201622b4a2b2de25ec7bdff85c7dbab744b95e3 GIT binary patch literal 301 zcmY+9Jx{|h5QaOTw2%o@v9K8l!9pT|7_LiDA(DqO(00mTInISxT;j+dApU(FDh9T@ zlkR<<_hhk$<@<|K0MEnE27PCmYN_X(oh#{tGW{4lHVGuJC1(%2&Z2C#vPFQs*95Tj zR*%>`Jp!ze==$H+Dk)1y$54}22Cj~rjkKR(1c=bk%MaVyp3(e};QUecPRbNK-tK4L!r literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/Cell/cdesc-Cell.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/Cell/cdesc-Cell.ri new file mode 100644 index 0000000000000000000000000000000000000000..ffecb6b67e306053764216f660822edc1f486e65 GIT binary patch literal 862 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 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/expand_table_unless_stale-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/expand_table_unless_stale-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7cff00423c12ff1ee5abfd5e632757655b8c5dfb GIT binary patch literal 321 zcmZ{fze~hG5QVRhcz9wJYy^u4qK!!*7IRHR4Wu{=@2*O*Y?6stoa~03i9h~(S5NJ1 zAH4T{Z*RVZ`03s?0JrvIh0?pWip_qRoZ|baZL37rgle*c%!)-5Mi4y|WdfVtqi)x_ zLx8Oq0$7VTBepl!XaAR%QBlC*=*_DZba1kRue5)eMu1>44QOQ!i+t2xxSGL1-WkF& zIVV%6@(ooSsOc1-DgQFBd>t*L4P?0+jHo`i8T-tt^KSTg;X2hgD`B5ijpW|4EURW^ l5??fv_aRmd67l8NPQC~qkNzHosA!INvX9OWn(jz5XP=V|Y=Zy* literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/free%3f-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/free%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3b3e91dc7b4a3389607c70b6911c7b072f9245fa GIT binary patch literal 268 zcmX|+u};G<5I{R1w`vhn#ljXO1Pk$i7_I|BK%@+1pzV~wa*{K#aB`7-0rB^^M6jOj z-g|elIKcYtnQDN?{(FnuQd6$&yhxVDBR&WaFL{w%?OTt!*=d6S2euAi$KDRu+}~YJ ziyM*Wa5{MVsTm0_Cg@iCk8uEqhOxt*7qH3(?KzY)SZ2mLjBsbGlz#;(L_<18K^p$} zx4se^u?Lw^XIZte!}jk%8Bd*JT{%=_R82iceoz%U`jS$Xvm%*a-yBb~Rea&>KRAx^ Q`h4npCEscHi_@% literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/hash_code%3d-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/hash_code%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e2daa8026164cc992d732161572c691566518096 GIT binary patch literal 282 zcmYk1K}*9x5QTe?wU}Zr#f!HHq6lUW#lsXKq7CHG9&CHcVc8^;?&2mJb|;GezFUjp zb$IW6-<*wiFnfQq6~IgPy+Ts9E@t{XkEcp{B`RCvGXu8F^7vt^9Ljnl8wA*qHUJxP zy2tuye)BKAU|9x}-sw+CXyN)azmo1_=m7$2XtAR)L}@P_`CD1@vYHiLO&GY z111>)CGo$IM^~~1+X7E*t4XLJqr1HqjkB#FSsE0!3CbOXeJ@Hh_KR~~jPf|TI||+( a>uD5zx%@K^r>wde_B$?cqMrHW+44`P2nS}@UkTB7QqHZOVBn-x+WpG;YyluSHX_Lk_(FcE5Wl#za=%!!=!Z@Cg#V& zSZBL<5UQHnv~sq%T${Ais!lCtf>KpFrP4Z{Ni!1aD+q#QFZK_vZ@Sm;)QKMcYIUb5 QKkMzhDP5y@7HCZH4Sd^=+5i9m literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/internal_reset-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/internal_reset-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..98f162f19cc00d4b2bd1f824d41f7f4a40ab3cba GIT binary patch literal 382 zcmZ9IO-sW-5QaU-T0iK;;zbWj1W^i25b?0RRMbEY6|wCphh>sXn#Ij-*qv1T_pU7p zdL7=G_nBvZuo9!UCtC{fU_R$ajji&LI>@3^WeA-CEggC!CfIYDMe(w62-N~=6k

    >aMNC_G z=>vV-2l&|kuuojEjVCkPDw0k3QJJ-uwX>}xC^Sl2%hCoXhP*6L+m9qk^1Un?T`QwV g1yS4Do9{cbVQ@A4H4{c@dA9rQ#kv;sqXzGjFX8-t3IG5A literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/new-c.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..0b98ce97822ce4bb9404b2cbfbd37519a21ce8e3 GIT binary patch literal 264 zcmX}nKTpFj5Qgy%D2<53RI#u{0>MH&AckWJ;*XS}9cVgbuWQ5JSLF5)m4674<1#wS3Lq8*jRu)doyA8_yDln zJtgloWYeszX$h`Q;8yvsc>;*~Jfh)X3!T4wQqi~roEw7op_ N?Z}VHzE~B4_yJn3RJZ^D literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/retry_update-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/retry_update-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a51c7c12bc70d39d4dc84a0fd22120b31279dea1 GIT binary patch literal 936 zcmZuw&rjPh6y`9crAQ1mv>mpCm7!@9rR@Rj;2ze(s1~VA(+Z~^qL<`_Sas~kb_(UM z-*YmUD!4?B-;eKm-~0Tkd&7_Z{Lm@qQ?58$`plpe z4;1LLU>saWAy0|D^O*|o*ab>y`;6KSwPC4Njwn&xfGrRiBzlc3r$}4-9q%g%s_8sn z*M+dGY}8`5&T}-DxdK^jYmiK7bz17ImSBY2{A+Mo8J$Qh8}7Ptq7>GNlt_}y1fQWN zEH|E>R&-1YOjnpOi>|3@dF=TG*n$6frr9|WT+M~T9X;-O-GV55JvFzD*p|07@3(cH z6N?V-P28qJ-kVR)FXyxs;fUz6`)qSQJEB;JawH@uJw*59{>1n8fd7H_y&h|jH8!~8 zgULwQ&z`33vpcYHt=j4gv#%a%a!T)N|LGOc)hvD2uIQIG LCCCd2){g!H+V?2S literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_in_busy-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_in_busy-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fcc80af36f96424eea586dd425f619488b23827e GIT binary patch literal 286 zcmYk%u};G<5C-53$gL=<7%CPvBUK=wCIe!)Egqdsw``xC-FOjvIxotILI+FnWo86w)Z}8eTbz@qXY^8TXxKj3$SzGGTOb ddv_@FS$t>y7e2O%>gt&C&G}B4XCp$$egIdRTzLQh literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_initialize_cells-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_initialize_cells-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d534b643bd1ae523ecbdb80c062affa39be702ad GIT binary patch literal 305 zcmZwCu}i~16bA4P5{s2iMGzN>APQn`P>0tgVhv=dgKeh_$0d339$s?c?nSMCy{APd z*9Y(Wec#@A1GDFatpM)3?Gjnrx|q>^9v`#YO6rJ78Tv$7p)o#!=rPOV+qHJ6>Xm8` zV8dhpR_v(9`tIiJ-@kd3WpLO#dQ*%RPIlx{x!0iw2>#Gw$77hJy>je}5geoq8O-Bz zLuJB0p7a4shTtXsm%DalG>_IGQri+s9coec;$`D(D_NBWrEO$oI}Z6?mT2s|5TY36 k@$};3>QpPQFTWGgNfMwgHhg#FD%q$dH?_b literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_to_install_new_cell-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Striped64/try_to_install_new_cell-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b42a62261b369386fe9631893bbc124f60057f16 GIT binary patch literal 318 zcmZ{fu}i~16o)&=S*$o!7ab&mD2T}*BCkuN8pu!w+fErCm*mA9Uhcx(i>3d)r=@PL z58m(lzJu`^rtdGd0(dst1#xTZVyX`F=z`rA*`hL@rPgR@gB58lK)hyo^t5Un$$BXp z0$8)s084hNr~2{X>c7{S$TB$Yo%)hY7S4Czg>;`o4-hPdjtq}slJ?TEFGg^bHcC?- zU29dw{EI{%nDG#hvELK#T`6W_1xac<#n=WjWj;JM&UVPM)P%Od${G&)9!t`8lO#zo m%A?bpec9b*D}8(WGn7t3;>ll7IAzt@&i2i^PU^Xq-Y4H34QkQ= literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Volatile/attr_volatile-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/Volatile/attr_volatile-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2d47d193e25000731e4dfb6ffb3eabaa443b6139 GIT binary patch literal 944 zcmZ{j&2Q5{5XCtlCo~`giUd+Qj1oZ;QWBTrMn#E$NI?p!+9sDAthGIkSFCrf-E~V5 ze>`Ky2@M|?Th_jr_uJ>0hs`BxUw+aNV^ejvK$q%x-4=~`=Q(%I1UFi8CnS2z`#hU> z-d(2#d3?naWNb+XjIC-#_fS9fW;52xi%^P4v*WGBf}3we&KUU>87kLgtx3*}v+IUt zuMRaA-0+RzdFqWHt%*ln7=0sRv@qB~4WK6!xD?^bYH?!0qO#bB5=4ZBL*P+_)@oxx zWVyuB5@R~oIq0M+988_gM0AM>8dMPu>=3-McRla4mX>djl^=icuh4`POV%K?_Pp~n zlH6LDX??VO71tZQ~*0n z0DM<4vPvvmpHOS*-ns?=xm~4dPa#Yj>3qwHWdUWBPhggoNY3J0qw}R7z@kO+vP1Cl z_@#X3a>B?KlGIk(iv!B*`n46Mvz72NH%i!26t?y#(~4Xf`<}3A!e$Ad;3FJ;geOxy zXq0EuG{TyH%JYB+Sv)I@Y}=l~DGwlQy4>gjMFKc)ob{^kYCnYY#_6N4FDr-nX#`f1H0e?)1L*_~8LIsH1Josh%W1b_T~Jjk0+0 L`$|2y_~Xc*KLwZb literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/cas-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/cas-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b80e65b3c4c0fd7918ac0be5097f8dd72febc5ae GIT binary patch literal 299 zcmY+9zfXfu6ooq&B(gP)i-~D)sc9q3*9D`JFw{Y*3&YC;9`fSlUGjdk@xS*`T-?rZ z@_pxAga=r?zfc44q<;3o_S9A@d0E6^!%YCeYgxpbve$yQAG{L)2P+ZalaTu$N;jgo zo2rjNoA0`^cOQHV^{zH literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/cdesc-VolatileTuple.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/cdesc-VolatileTuple.ri new file mode 100644 index 0000000000000000000000000000000000000000..50e6cc925954c6e3949cb55c99d54464da9622aa GIT binary patch literal 1107 zcmb7EU2oGc6zu~_LfcWs_)rBBA$+LSrZ&9raHFB1u}OItAlB|B50R5Pts#jc+gS&{ zp6jITT9`oOA&GO3&pq}z&K+wCkH3E83BV^Va*~~7M9T1hS%LH5l4nG*j83XDqXrnK zXMyu-vJjNaE=WoNrdS2og?R>|I-lcjG*O0UOgKDk_|J*>UX=jYtjcMjEa>b&*8x#uZvO-Y8ev;gN{z*{;uXrlJMf%!;{;Qo-{`kvO9fPosnv3f+@Y zOf$Z8y{_x+xnV0brf|@hcft#)NTI?WYXwfbNlzV%!+(SaU;}pDRVZ3s*Y9HszwevL zpHX!~BgCxsP74f`&?0MVn?SAS{@40LQzxyR=!2lSLQEcX$|}xSg3YjIVF+}^A7JHP zDY(L{(;04p3Efh#E25|#1kN6-w<4)UX(F!|c4`XrdQA~H4-=l_QJ@hiW;#V!In(5U zbC;3?!@n8o+}{lMHwI#|Zu`8&<=xkkynVdaX01*onx*Kq0=U36FkXZfYi(_PZLZ<> V1Lx82-syhHlkI=UIiFP-{RIJ_O0oa| literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/compare_and_set-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/compare_and_set-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..34262c519181a260ce4835903dd19c20dc7ee0dd GIT binary patch literal 350 zcmZ9|u};G<5C-55D1>H15epKk!UCcq9+=Kc5D+Ot86aiJU^$LMEgWAIJFR&8I)nwb zlXd6s{yPb`5WhX60C+Ut8|ik~RIxfOl2~BZ^FcCh8fK*nAb81(l3( zG{6UH?h9Fty_VPi$7qn}5cOlNl|ZVO6%kPJKJ*v@aJ%%^4TfE{zZ){)FsXdGQ8P5NN_RqPvn4`Vo L&~g2wxwYg7iuiI! literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/each-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/each-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..aa87bec537855ab55518cb9da0be53ca169b731d GIT binary patch literal 287 zcmY+9y-&k16vR6qH;@fgENo_>LL!-8mmnaLhcc9uC4*(VFO7v0NB#iu-{Z6_Y^SGp z_q)5u_ORN$SOxGj{%kSy_Ry~MlF>^PswY5RYev^i?@%1xMTY?Upbfx>H6jUY;$-md z^t&N-4fzzM(aOT@Idv=CXPf{MA`Uo)4DxCcF8Fo~~o*njJCB#&*Hz@_s$b ZDo>NH{|!jzTHTx*zgag3^K69o5pxJLx~u1dt7B)Gn4#HIwu)v8Ol&nmJF7iI>hQF7x@DOzaF<`VLP4f zeV^y1^F1tf&(r{HhVQNR9Ubb0nU(34Ge4REdnw9vRdrU&!<%e1z}_1Kcqf!`&{Y^w z-<@yQtSBHEgF@2~++JF@(jLPI5D}r*gP%i^kJ5TqPvAOlV?&ufpi!AWBZP~LEX3yQ z^N%3>3GrwZTeAvyPQCG>i#lfbaH6%;3ojLFL9J+L@DbvK(nw#N^LkRIv-{O4nkVs- Vn}6PMT{O#!=quS?;uA{e_%BzbTe|=N literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/volatile_get-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/volatile_get-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b40e35f03ffb15b19859983589ec8d0634c7b162 GIT binary patch literal 295 zcmY+dxey?=san~%&d6msS(aK<~7JD5Su-CH69_!v|xqFwL2G~#&VEZ>! z$I0rOlbt0iOGu}vtZ5OhkIG8Ak2nDk83#Rv1kz%XF8F2!7ez;2mEBvT^6*OuPgWj@ z%KvYN1NGn(Te2E>frAO6r&wm(d(k-@M39PdV<%c110h~0ZSjk9-pr~jxixo(-6Exz WE>9kya@k%TldjPX(mq@1J^umDvSPge literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/volatile_set-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/VolatileTuple/volatile_set-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5a329170f619ac8573ad722480e97bef90fb385e GIT binary patch literal 302 zcmY+mYq7p!pTMUxrl#{OA%7n z`+D9xnyz8~`h*R@!|=V*)ZwO{o8vM)-J+FbtQKAq1NK~$>3!8XEjMqn)d1_*1bF|O zs={dX)xpk^6$K=EhbuI8a2qP}<@b=e(Yj>1<(cFSpVL deZ4!8C-JkhgFj-qXwLV6U(of^K3eHL{{gU0Wkmo0 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/cdesc-XorShiftRandom.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/cdesc-XorShiftRandom.ri new file mode 100644 index 0000000000000000000000000000000000000000..e8b648b3bc7140301c3022dbc4e01bb35d174e4f GIT binary patch literal 1168 zcmb7D?`zXQ7_J~`SUWcvL#To;8Nxwjj@&vKLhTC<{WcN13r)o22I!RBGiL!s(ih z>30Qru^Ib~O1hA=NDRD2Adh~Y!b(V0VF6i#fxOH@CgHFUifewuU^wP0JRGVcSg@Q) zs)c+Fg%meDW(p9q5;+aiTZj@y3s}-y&|)3SK-aV&6%kE0n`ai{tQcA5jvQ3gby7>lmODql zo^_n^@T36{DD>G$i8ebyh(T?Ew&+NPb-wM2jOzf0S`9`8b1AYwEZ#+Hy@Z~J7k^d67uDSL{mG8dsyUuRa%z27yt!4Y#QA>^f cAY_8*xX68zckU3cwKv>>XYJpYvMzk^3$t%;j{pDw literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/get-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/get-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..87d37ed755bab86046b0209750bb4f3de7a35dfd GIT binary patch literal 385 zcmY+A%}c{T5XC)6S}l07;6V=|UM!()&eKZ-O$kzwet?j}vPmY*;_gn^Y-;tdcT-Qj z4)48rzjry@!Fc^b1;DfZS)r||%*JAn2E#pC54_hT4JO;#ATKw(LV%qW65x}}rWTc5 zb6t{p?6nIoNnq4;xfBJ#{eS3+o3E|`a34B_+74k9H{94Z^9UZ!H6PsYz2QymEv_;z z4VFvPXt>4J=h_!qSiz;QNl$;#kl#@2E(i3(L>zUeLjNGRAHJc{C}+kM3ums>7Ovw; zNKAvN6#3kqP+03&=AA>CAIY$`M`68%)Xd~3R}_;Hmemei=zYs7LyB3ROJr2Bg0yuw oEz42TcN9h0MH&pACcQPjahu(qFVwG7-2L;ulTlo*sO%(0f1BukWB>pF literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/xorshift-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/XorShiftRandom/xorshift-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cb342e7a23ff967e6b4d1b9eb6485fe1bcc71da0 GIT binary patch literal 455 zcmY+AOH0E*6onNeR*P;dxX{HAH!Z|AMOTv=qG%wCiu3_O7Q-Z+G=r0wFpoaKwSUe( z{aG z#a`y+J)lj^$iBV8%n${-cizw&-rJD?73H*|ihw7&iIKSMpdbKZNHWmxRi2nnPftYOo literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/cdesc-Util.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/Util/cdesc-Util.ri new file mode 100644 index 0000000000000000000000000000000000000000..eb84657b840ba16938cf9b38c84fcb2e904a05d6 GIT binary patch literal 1212 zcmai!&2Q5%7{+@*N%}dY4iI7j6luF4+8ibh&c&mwk`FCtZKR1DEZ1?UH8+kNXWgHV zlM=OME?gox_VasQzweX0@FMW$?wh0l%%$28F_TFtSUlt&^4pQ-!U4|h6#1`~YsE;i zASnZ&ejhs1K!SHW@rl32f8pPN*D1!hOQTSaSL={$^}FIh2X2Pu5q|9 zym4u4Mr!4R&JqMrZn(y4Imkpp8Gpilt1kj553SlT}Mi)j1ZDK2-JEm1C$j!deupOAe#I3j;f#EJp z6PXp7WI8_ME##k1(fvG{;jd_k7wG4$iHXVM)!%spz;Z4)m^kbkAJ~U3wFEwh!tTzl zH@msVXujOpynk+Uuy4h~(H=IK{D|=6d(_}QKF1xM_%HDMrq1VG6VH>)u$()B536Pj zp=+u&y?0|5`5h`qQB+@H?8PqV=H*IoTJ3^CuB2vEv!q`3a>XBsX4L}ueO`}?vPK&A zs*SK;KL_U7ik+zWQ<&ju_M`z=7#^2d?D5vYlR!XQ@B)5-KDNf5VCGx7 literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/_mon_initialize-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/_mon_initialize-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e5a05d6ec257204873a0862cee81bdb55f720780 GIT binary patch literal 257 zcmZ9GF;BxV5QRG+w;}^eqz(*7VS$BuzAiz6NEyNaWy)}}6Q?<0`y$5?f?toJ15($g z_rCXCY~CS%ec}$_(SJ22j@-97t?MF3#~#U3BxUK_2oTRzUECbTU{wF626KDf*o&%y zY+AIXj^X-*ZB+PJCV=#@IOF36vT{-(&g}{=%Ym$^i>)QSi+^C86Zs)%u@?uBB|C~Z zrbF__8Hd0QqtezO57@Df2{@xRmOrJG?W!);clW>3GE1&k|E?*ky6ws6g@aSJ;eN43 F{s1x}Q_KJW literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/allocate-c.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/allocate-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..36c5abd5e8d3a2f4167c567a19194b11abd540b4 GIT binary patch literal 244 zcmYMuu}j1-6bA4cBzIWE<=_yvOuA_1cS{8=WT=DIsY6K8R~vloD`|@O-y1#9^?Q83 z_nqzDVE^*S9^hg6sxb}RwfnHu^1>3aw+RJ^r%KDKW{7CJSKA}N-|Z->28wxg6g_p%Qw$2+-LaqPwR zHVqH_?Tk0cO88gntM>?w2qk3Ekn{+57^nzn42B)sz zN-UDSHiK$Zy$ickPlQWGm_w+KHW?Z{NgNwUNc1q_S~(=P$pECDc9*PCqZgcQ5uP%K zOgu3#1Otjg!WkbyGGKfRDqZA@nj0ivZIcw3^4OQ#u@fVnlH<)bPHE+Z@!VjY?kN;M zZBy8p;v=J#_zTjf5Io-|$eoboGJ~?vQb*{F&RQ0)bu{r!O%p>s>PWY&TuQ{hHJ5hih|Eg5P< z+Dgbaxo0xRYp2Noh;`aP`ifXh7_k{}!6a$>{B4ZDohHH(1ApcM!#qZ)RB+~ixDk*5 z2|Eg`4PJYni5j$pf@zD^c!}3_`_ax^ck>rx*laHR%XQ(O&exPjEibXw3!=BcS#E(` z-Smh8Y&S8vLcux(tc##4qF9ixirU~oSch&$d}Y1h91Wo}x5kdQMpSNc?s9{zup^zz zl;k!?{ESSs8Iz$w$8eCvq5w2Y0e88oZOmke6tuS-^Um~M7WdX z11Wf1^>@2|zWhMUQ#|qlA!;u(+5vZvdfKp+8F7y={|~Z=VlB95DUw9H@vgu4BAK9( z3nd&5CK|ENLdX8*Fa>VFzle!lT>Rhns-P2Un~u)>#Y=CI3Hm_7B`}rb8NPmg)gi&1 znlgi)ZHuys@Ror=E@Zko*|V9%$9Evq>g-^Cre(T$e(cN))nW#(sc`2dDBAO_iuUnu zC9d|DKM!y?96Y!%yv5$4`^0roS-J*}USU8-xRLuf8b|aQJ)vLIZ|QgR1^tnBXqWy> S&+u!X^Mya%>Fg5K$$tO^$DJqu literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/decrement_size-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/decrement_size-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6a330cb4720e5e4dbbdf7c1524232ba6c0f1585f GIT binary patch literal 292 zcmZ9Hu}j1-7{zapcv!^20|!Bly6EE7#o;@I3R>t;2R)|_A4&SfhD(!@q{#W#oAU<2 z_3`-q-aDFqz~b%MNq{H2Ybf@vYZv;s&d)oNo(8fJgZ?H4?4_#nt4;5Tckf)$^}oWJ zRTX68B#f30E)UR#`|UIWB*V04%^@pC?qg_Ya8fF5sLmgZ7OVKn#gM=&9^IfNdQ#-c zN{dKXB8yZZcH-0BJ{H+5i9m literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/increment_size-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/increment_size-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..acb175cbd866a39cd58c58bab0388d0bb64f00dc GIT binary patch literal 286 zcmZ9HF;BxV6ofk7kGceZ+m_3qg#fG79WQW|{UtZ$i`UKf{*Q zH5Ah>HyNk~iRH7f5??u#hN`cKYzw`j`c-Tg6I Z75T}<-;=D>>gqK3)rV2o*7vg|{sT(bUuOUS literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/lock_and_clean_up_reverse_forwarders-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/lock_and_clean_up_reverse_forwarders-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8c9d6f17eea8725c27e13880afb57444f17c913a GIT binary patch literal 380 zcma)&F-yci5QVRhczA`)frU+ojR(O?A%c5N1P!E!g`QQ4VY53iOEx=UvoYwechBJ2 z+C668@Vn5`;!>VC=!-2igIlCOdH}y$)FL zl;zRwzOl&VE3fhDUuU}@%h;+PE3E{v%Nd~HwjF!MJk8jlaZ9#Jdv4uOF4$RGD~)+{ zr&YCeKWQ-dxGi_oDdEv-v}go^;G#jOxMI>u0;Pksvad_-wa|laUzLE34M*J)j7xRnH MWIL`4lB34t8yZD~Hvj+t literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/rebuild-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/rebuild-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e6c68280662f56043b6c1e48d7cd8e97380a115f GIT binary patch literal 397 zcmY*VJx{|h5M@B2Py|b*4lr0@fu+sF;4VReNEw0)Eot;Z#)$v7+L*d_JQX#~4 zckko$-tpv(&t4x%asFVx3iJ(CR?lV+YKG(!Ea>jV_`RSH>>1c&G5SffL$P^jRKLW0_%trkv>@+1u`FPe~F+ifpuN39q?3#x@8>qE|7 oNHnxhlB7He?cI*}-H$%K2>o6D^%riLnje~YCf9-~s2U6=-_SIJ(f|Me literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/split_bin-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/split_bin-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..dba608fbed5f5576a4f7c79132949893348d5c05 GIT binary patch literal 305 zcmYL^Jxjzu5QeXico@*;K*Z*V77B-#%3`mHpn(*z(6dT0?8n4iZnG11Hyr+ZS5sUw z#XB$0%yYKX=RZB literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/split_old_bin-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/split_old_bin-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..1fabcab62301be261f0d0014fe07b0cccd26f2fe GIT binary patch literal 457 zcmY*Vze@u#6n2oaT2PRJg9?wjD3talhjgi+2OTP6>r^DXOWrl1X>uf~NB?`%yFpw+ z^4^#4*Jw!L-53fUQbmY!RUTT}M?5&s&?^ntb$|Y9x@P9we zih}j)eQC6C?6#v^px^Fm#uER2M>h6Ye^#T9VVya4_aF0t9ycCql}*pr*?joDJn9EP zu+Hz$Kym?%jtYzp5md5463PP*Xd4|E2WTZI4Xwg7O+!RuLb||4|B!`)%~tGU zR%t`?;j_`@B(|Y=NU0_m-A)VcsUlBS5Em#E@e;+BtQ`BY{hrSfD)OTVZ8w2e-tBlx z&t1iZvoWO&yd>kAJkQrBN$IiOkHAvXK}Vp|%Sq}^t}v((RL(c(CHbeL((E#|e)ZRS Snib-vYwo@6W#Q!BQ2q;FHks%E literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/try_in_resize_lock-i.ri b/.gems/doc/thread_safe-0.3.4/ri/ThreadSafe/try_in_resize_lock-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fc0dc3df557672e88425de72cac2b975982243b1 GIT binary patch literal 324 zcmZvXF;BxV5QQ_KP?3S9QU?Z*SwKQG6N9@12_j_(1C%Ml$-Z2O6~~SoTd4ec+-6{5 zJ-z$h`_5LMeEt4nk@IJBsLA)XZPx0%VjJ%cpbR*g)enKTIHWv%Ei1mXm z3GLFd!g@SP_##FDxk|k$1;vHdCF@)F_=DiI9}nQ;~HzKjalv=|LNz z^;8m({#z@M`H0QO_>SdY{#y|a_=Lda1vASm)jlG;*_27NN2(cdop&D1#9&|w!LW-X9jyfIeva^L j)PE^}t>)976Ng&y@5%cDi90~gdN9vW^ literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/Threadsafe/const_missing-c.ri b/.gems/doc/thread_safe-0.3.4/ri/Threadsafe/const_missing-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..f2f1c157c8bb4d1545dd5dc920bb86268e37c39a GIT binary patch literal 312 zcmY+180YvI4=2_PMqt#WYzSvd(GLrV}=$C(e|#m0+iB*l447`-efueTy9Qji8N z%0U~&=!4O69rp^pW30Ez2aWF8%Y7~{(dx*@q)hC<2alFVA&ufV@I;P@5x7(afATzU jPZ-S}ov`X@w_aW~j9&jgnPydYdvLy^x5Cue&qn2c24H3Z literal 0 HcmV?d00001 diff --git a/.gems/doc/thread_safe-0.3.4/ri/cache.ri b/.gems/doc/thread_safe-0.3.4/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..5620ca2ce2ed5f995e4bf15a2eda21d4e18fb5b5 GIT binary patch literal 5336 zcmc&&>u(cB5a&Y`VkeFh=K&!pq}S4l3Mk@H(W|PO1`vk|R3ucDEOc7mt>bO()qCX8 z{PX?I?%sLNHYVf){dPCIJ3ITEncvLr7xQP!_7aOcp5<|xovl08#{Mwn%->@JZre}N zl%3AmbI+dlE<09J{r)_+?^st~zAgHvw!L>6dBZf0#J}91lOyYv?a^u@>I+|K?tTzi*` zz_$O0k9qoLuzwuy7l|B&rT5RR@^$PhjXKJ1or@!(E=VG;eD+ zj=UlT1o;>Ouy4my{wft?GbBdWU&qlb9p9TeX3d>M{Fb@YjD-n1fXd>lBIhS=sGN2F zT^;M1sro4o_yI$_k{*hIwLKBSVKup9ZJVYk*q``5r&aPCOM7`L67K)_P}%eCnws(0Dl!mU2rGYYcN>q)TC9|&mEGj~t>Oe!p z)ME3-+Fsfuq<;!o)2R` zJ8O5_G<81W$25$Eh=!E_@y~sC2#WZXHXBWtl?|1W8>Y&Sg-EsPwz;bNL+$U8`R7>e z5jG_jEf&CPmdix1W@O;Xaz@9Cqbzqrk!2z}AgR6KxeAUWmJ0Gic6Q0$@m!h^@H~#D z47b2{v5yH(VYi;?@8-Mx=XV}Uo$CU-5N}r)Zvf-39qV%MJxu_Xz4yPUuQhmxhe_^w zahSk$N_w@F9`M{{k?&@lSQIP2D@R0>^E6^XxzH5@m-RF7kec}A#Ke>*0rT_@>tJi| z&>h4S9vKRRTGjLd&SVyX5o#uF=)duOt{CzJswx8(d{9Aopk?*rCQNAUOB@Bm_+KCt zPIatp4+IW<#DapmB61_Jw;PB|A8mO8l~t19C_W#sBGA*;L?m*-0vrw?B^3Ms5YDNj z`H0~muH#wF*5Vp^4djwGwS`ZaCTc+&>3qPAb8YB_gd0D>88S6-rIe2#X^i}^DosNa z!glybEm_UeQjwG8g$Pfzop|;1W8f5!oOGwA4Kk%rJV3B@%8FX>H3u9PYxCqcg%qfY#W8=)|w-iBNGv7rf;T>9Ah@d;dKB;^EtP2wHx^NVrR zrc8;7Efif(L{!)6ZA^v#e+K%Tz|Mm3VzAY+ZAR}r?^vs8811SooeLbFCIN456j z<4D0iv#V|*m6@-(Wy$AW%EPKyFNvu3-=s>etHyj*NcQR8rdrb>?xtczD|y3S7$YKT;QL_OeWWzlV^ z3nS1Oq@0(vMw*INP4jlU`q$0ZYE|@&E2Kb^0$COm1(*_=^g>e z(K^B74NV{ob|YjWx@Rwj^4^y9wq{+9s!I$#_$UKv%})8`gIzx5Y33piCyw>lJo?zJ z*L+a0ZF+1`=qQ^n@bdGaOD6hv(~K8YA6dKNPkCzT-gK;UzlV(NLVi{!nMJVOtBy70 z-C)Wy#n{8pln05anx?!!IMzqr2pnrl!jz8) :mri_19 + gem 'rubyforge' +end + +group :test, :development do + gem 'rake', '>= 0.7.3' + gem 'rspec', '>= 2.9.0' + gem 'coveralls', :require => false +end + +gem 'idn', :platform => :mri_18 +gem 'idn-ruby', :platform => :mri_19 + +platforms :mri_18 do + gem 'mime-types', '~> 1.25' +end + +platforms :rbx do + gem 'rubysl', '~> 2.0' + gem 'rubinius-coverage' +end + +gemspec diff --git a/.gems/gems/addressable-2.3.6/LICENSE.txt b/.gems/gems/addressable-2.3.6/LICENSE.txt new file mode 100644 index 0000000..ef51da2 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/.gems/gems/addressable-2.3.6/README.md b/.gems/gems/addressable-2.3.6/README.md new file mode 100644 index 0000000..9381a67 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/README.md @@ -0,0 +1,102 @@ +# Addressable + + + +[![Gem Version](https://badge.fury.io/rb/addressable.png)][gem] +[![Build Status](https://secure.travis-ci.org/sporkmonger/addressable.png?branch=master)][travis] +[![Dependency Status](https://gemnasium.com/sporkmonger/addressable.png?travis)][gemnasium] +[![Coverage Status](https://coveralls.io/repos/sporkmonger/addressable/badge.png?branch=master)][coveralls] + +[gem]: https://rubygems.org/gems/addressable +[travis]: http://travis-ci.org/sporkmonger/addressable +[gemnasium]: https://gemnasium.com/sporkmonger/addressable +[coveralls]: https://coveralls.io/r/sporkmonger/addressable + +# Description + +Addressable is a replacement for the URI implementation that is part of +Ruby's standard library. It more closely conforms to RFC 3986, RFC 3987, and +RFC 6570 (level 4), providing support for IRIs and URI templates. + +# Reference + +- {Addressable::URI} +- {Addressable::Template} + +# Example usage + +```ruby +require "addressable/uri" + +uri = Addressable::URI.parse("http://example.com/path/to/resource/") +uri.scheme +#=> "http" +uri.host +#=> "example.com" +uri.path +#=> "/path/to/resource/" + +uri = Addressable::URI.parse("http://www.詹姆斯.com/") +uri.normalize +#=> # +``` + + +# URI Templates + +For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt). + + +```ruby + +require "addressable/template" + +template = Addressable::Template.new("http://example.com/{?query*}/") +template.expand({ + "query" => { + 'foo' => 'bar', + 'color' => 'red' + } +}) +#=> # + +template = Addressable::Template.new("http://example.com/{?one,two,three}/") +template.partial_expand({"one" => "1", "three" => 3}).pattern +#=> "http://example.com/?one=1{&two}&three=3" + +template = Addressable::Template.new( + "http://{host}{/segments}/{?one,two,bogus}{#fragment}" +) +uri = Addressable::URI.parse( + "http://example.com/a/b/c/?one=1&two=2#foo" +) +template.extract(uri) +#=> +# { +# "host" => "example.com", +# "segments" => ["a", "b", "c"], +# "one" => "1", +# "two" => "2", +# "fragment" => "foo" +# } +``` + +# Install + +```console +$ sudo gem install addressable +``` + +You may optionally turn on native IDN support by installing libidn and the +idn gem: + +```console +$ sudo apt-get install idn # Debian/Ubuntu +$ sudo brew install libidn # OS X +$ sudo gem install idn-ruby +``` diff --git a/.gems/gems/addressable-2.3.6/Rakefile b/.gems/gems/addressable-2.3.6/Rakefile new file mode 100644 index 0000000..46d3e82 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/Rakefile @@ -0,0 +1,37 @@ +require 'rubygems' +require 'rake' + +require File.join(File.dirname(__FILE__), 'lib', 'addressable', 'version') + +PKG_DISPLAY_NAME = 'Addressable' +PKG_NAME = PKG_DISPLAY_NAME.downcase +PKG_VERSION = Addressable::VERSION::STRING +PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" + +RELEASE_NAME = "REL #{PKG_VERSION}" + +RUBY_FORGE_PROJECT = PKG_NAME +RUBY_FORGE_USER = "sporkmonger" +RUBY_FORGE_PATH = "/var/www/gforge-projects/#{RUBY_FORGE_PROJECT}" +RUBY_FORGE_URL = "http://#{RUBY_FORGE_PROJECT}.rubyforge.org/" + +PKG_SUMMARY = "URI Implementation" +PKG_DESCRIPTION = <<-TEXT +Addressable is a replacement for the URI implementation that is part of +Ruby's standard library. It more closely conforms to the relevant RFCs and +adds support for IRIs and URI templates. +TEXT + +PKG_FILES = FileList[ + "lib/**/*", "spec/**/*", "vendor/**/*", "data/**/*", + "tasks/**/*", "website/**/*", + "[A-Z]*", "Rakefile" +].exclude(/database\.yml/).exclude(/Gemfile\.lock/).exclude(/[_\.]git$/) + +RCOV_ENABLED = (RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.8/) +task :default => "spec" + +WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false +SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS']) + +Dir['tasks/**/*.rake'].each { |rake| load rake } diff --git a/.gems/gems/addressable-2.3.6/data/unicode.data b/.gems/gems/addressable-2.3.6/data/unicode.data new file mode 100644 index 0000000000000000000000000000000000000000..cdfc22418a51396f2b89cfc1afb2c892b30d7e3f GIT binary patch literal 115740 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 HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT && + ch_two >= HANGUL_VBASE && ch_two < HANGUL_VBASE + HANGUL_VCOUNT + # Hangul L + V + return HANGUL_SBASE + ( + (ch_one - HANGUL_LBASE) * HANGUL_VCOUNT + (ch_two - HANGUL_VBASE) + ) * HANGUL_TCOUNT + elsif ch_one >= HANGUL_SBASE && + ch_one < HANGUL_SBASE + HANGUL_SCOUNT && + (ch_one - HANGUL_SBASE) % HANGUL_TCOUNT == 0 && + ch_two >= HANGUL_TBASE && ch_two < HANGUL_TBASE + HANGUL_TCOUNT + # Hangul LV + T + return ch_one + (ch_two - HANGUL_TBASE) + end + + p = [] + ucs4_to_utf8 = lambda do |ch| + # For some reason, rcov likes to drop BUS errors here. + if ch < 128 + p << ch + elsif ch < 2048 + p << (ch >> 6 | 192) + p << (ch & 63 | 128) + elsif ch < 0x10000 + p << (ch >> 12 | 224) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + elsif ch < 0x200000 + p << (ch >> 18 | 240) + p << (ch >> 12 & 63 | 128) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + elsif ch < 0x4000000 + p << (ch >> 24 | 248) + p << (ch >> 18 & 63 | 128) + p << (ch >> 12 & 63 | 128) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + elsif ch < 0x80000000 + p << (ch >> 30 | 252) + p << (ch >> 24 & 63 | 128) + p << (ch >> 18 & 63 | 128) + p << (ch >> 12 & 63 | 128) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + end + end + + ucs4_to_utf8.call(ch_one) + ucs4_to_utf8.call(ch_two) + + return lookup_unicode_composition(p) + end + (class < cc + unpacked[i] = last + unpacked[i-1] = ch + i -= 1 if i > 1 + else + i += 1 + end + end + return unpacked + end + (class <= HANGUL_SBASE && cp < HANGUL_SBASE + HANGUL_SCOUNT + l, v, t = unicode_decompose_hangul(cp) + unpacked_result << l + unpacked_result << v if v + unpacked_result << t if t + else + dc = lookup_unicode_compatibility(cp) + unless dc + unpacked_result << cp + else + unpacked_result.concat(unicode_decompose(dc.unpack("U*"))) + end + end + end + return unpacked_result + end + (class <= HANGUL_SCOUNT + l = codepoint + v = t = nil + return l, v, t + end + l = HANGUL_LBASE + sindex / HANGUL_NCOUNT + v = HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT + t = HANGUL_TBASE + sindex % HANGUL_TCOUNT + if t == HANGUL_TBASE + t = nil + end + return l, v, t + end + (class <?" + + "@ABCDEFGHIJKLMNO" + + "PQRSTUVWXYZ[\\]^_" + + "`abcdefghijklmno" + + "pqrstuvwxyz{|}~\n" + + # Input is invalid. + class PunycodeBadInput < StandardError; end + # Output would exceed the space provided. + class PunycodeBigOutput < StandardError; end + # Input needs wider integers to process. + class PunycodeOverflow < StandardError; end + + def self.punycode_encode(unicode) + input = unicode.unpack("U*") + output = [0] * (ACE_MAX_LENGTH + 1) + input_length = input.size + output_length = [ACE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + delta = out = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: + input_length.times do |j| + if punycode_basic?(input[j]) + if max_out - out < 2 + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + output[out] = input[j] + out += 1 + end + end + + h = b = out + + # h is the number of code points that have been handled, b is the + # number of basic code points, and out is the number of characters + # that have been output. + + if b > 0 + output[out] = PUNYCODE_DELIMITER + out += 1 + end + + # Main encoding loop: + + while h < input_length + # All non-basic code points < n have been + # handled already. Find the next larger one: + + m = PUNYCODE_MAXINT + input_length.times do |j| + m = input[j] if (n...m) === input[j] + end + + # Increase delta enough to advance the decoder's + # state to , but guard against overflow: + + if m - n > (PUNYCODE_MAXINT - delta) / (h + 1) + raise PunycodeOverflow, "Input needs wider integers to process." + end + delta += (m - n) * (h + 1) + n = m + + input_length.times do |j| + # Punycode does not need to check whether input[j] is basic: + if input[j] < n + delta += 1 + if delta == 0 + raise PunycodeOverflow, + "Input needs wider integers to process." + end + end + + if input[j] == n + # Represent delta as a generalized variable-length integer: + + q = delta; k = PUNYCODE_BASE + while true + if out >= max_out + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if q < t + output[out] = + punycode_encode_digit(t + (q - t) % (PUNYCODE_BASE - t)) + out += 1 + q = (q - t) / (PUNYCODE_BASE - t) + k += PUNYCODE_BASE + end + + output[out] = punycode_encode_digit(q) + out += 1 + bias = punycode_adapt(delta, h + 1, h == b) + delta = 0 + h += 1 + end + end + + delta += 1 + n += 1 + end + + output_length[0] = out + + outlen = out + outlen.times do |j| + c = output[j] + unless c >= 0 && c <= 127 + raise Exception, "Invalid output char." + end + unless PUNYCODE_PRINT_ASCII[c] + raise PunycodeBadInput, "Input is invalid." + end + end + + output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "") + end + (class <= 0 && c <= 127 + raise PunycodeBadInput, "Input is invalid." + end + input.push(c) + end + + input_length = input.length + output_length = [UNICODE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + + out = i = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: Let b be the number of input code + # points before the last delimiter, or 0 if there is none, then + # copy the first b code points to the output. + + b = 0 + input_length.times do |j| + b = j if punycode_delimiter?(input[j]) + end + if b > max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + b.times do |j| + unless punycode_basic?(input[j]) + raise PunycodeBadInput, "Input is invalid." + end + output[out] = input[j] + out+=1 + end + + # Main decoding loop: Start just after the last delimiter if any + # basic code points were copied; start at the beginning otherwise. + + in_ = b > 0 ? b + 1 : 0 + while in_ < input_length + + # in_ is the index of the next character to be consumed, and + # out is the number of code points in the output array. + + # Decode a generalized variable-length integer into delta, + # which gets added to i. The overflow checking is easier + # if we increase i as we go, then subtract off its starting + # value at the end to obtain delta. + + oldi = i; w = 1; k = PUNYCODE_BASE + while true + if in_ >= input_length + raise PunycodeBadInput, "Input is invalid." + end + digit = punycode_decode_digit(input[in_]) + in_+=1 + if digit >= PUNYCODE_BASE + raise PunycodeBadInput, "Input is invalid." + end + if digit > (PUNYCODE_MAXINT - i) / w + raise PunycodeOverflow, "Input needs wider integers to process." + end + i += digit * w + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if digit < t + if w > PUNYCODE_MAXINT / (PUNYCODE_BASE - t) + raise PunycodeOverflow, "Input needs wider integers to process." + end + w *= PUNYCODE_BASE - t + k += PUNYCODE_BASE + end + + bias = punycode_adapt(i - oldi, out + 1, oldi == 0) + + # I was supposed to wrap around from out + 1 to 0, + # incrementing n each time, so we'll fix that now: + + if i / (out + 1) > PUNYCODE_MAXINT - n + raise PunycodeOverflow, "Input needs wider integers to process." + end + n += i / (out + 1) + i %= out + 1 + + # Insert n at position i of the output: + + # not needed for Punycode: + # raise PUNYCODE_INVALID_INPUT if decode_digit(n) <= base + if out >= max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + #memmove(output + i + 1, output + i, (out - i) * sizeof *output) + output[i + 1, out - i] = output[i, out - i] + output[i] = n + i += 1 + + out += 1 + end + + output_length[0] = out + + output.pack("U*") + end + (class <> 1 + # delta >> 1 is a faster way of doing delta / 2 + delta += delta / numpoints + difference = PUNYCODE_BASE - PUNYCODE_TMIN + + k = 0 + while delta > (difference * PUNYCODE_TMAX) / 2 + delta /= difference + k += PUNYCODE_BASE + end + + k + (difference + 1) * delta / (delta + PUNYCODE_SKEW) + end + (class < '?', + '/' => '/', + '#' => '#', + '.' => '.', + ';' => ';', + '&' => '&' + } + JOINERS = { + '?' => '&', + '.' => '.', + ';' => ';', + '&' => '&', + '/' => '/' + } + + ## + # Raised if an invalid template value is supplied. + class InvalidTemplateValueError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class InvalidTemplateOperatorError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class TemplateOperatorAbortedError < StandardError + end + + ## + # This class represents the data that is extracted when a Template + # is matched against a URI. + class MatchData + ## + # Creates a new MatchData object. + # MatchData objects should never be instantiated directly. + # + # @param [Addressable::URI] uri + # The URI that the template was matched against. + def initialize(uri, template, mapping) + @uri = uri.dup.freeze + @template = template + @mapping = mapping.dup.freeze + end + + ## + # @return [Addressable::URI] + # The URI that the Template was matched against. + attr_reader :uri + + ## + # @return [Addressable::Template] + # The Template used for the match. + attr_reader :template + + ## + # @return [Hash] + # The mapping that resulted from the match. + # Note that this mapping does not include keys or values for + # variables that appear in the Template, but are not present + # in the URI. + attr_reader :mapping + + ## + # @return [Array] + # The list of variables that were present in the Template. + # Note that this list will include variables which do not appear + # in the mapping because they were not present in URI. + def variables + self.template.variables + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # @return [Array] + # The list of values that were captured by the Template. + # Note that this list will include nils for any variables which + # were in the Template, but did not appear in the URI. + def values + @values ||= self.variables.inject([]) do |accu, key| + accu << self.mapping[key] + accu + end + end + alias_method :captures, :values + + ## + # Accesses captured values by name or by index. + # + # @param [String, Symbol, Fixnum] key + # Capture index or name. Note that when accessing by with index + # of 0, the full URI will be returned. The intention is to mimic + # the ::MatchData#[] behavior. + # + # @param [#to_int, nil] len + # If provided, an array of values will be returend with the given + # parameter used as length. + # + # @return [Array, String, nil] + # The captured value corresponding to the index or name. If the + # value was not provided or the key is unknown, nil will be + # returned. + # + # If the second parameter is provided, an array of that length will + # be returned instead. + def [](key, len = nil) + if len + to_a[key, len] + elsif String === key or Symbol === key + mapping[key.to_s] + else + to_a[key] + end + end + + ## + # @return [Array] + # Array with the matched URI as first element followed by the captured + # values. + def to_a + [to_s, *values] + end + + ## + # @return [String] + # The matched URI as String. + def to_s + uri.to_s + end + alias_method :string, :to_s + + # Returns multiple captured values at once. + # + # @param [String, Symbol, Fixnum] *indexes + # Indices of the captures to be returned + # + # @return [Array] + # Values corresponding to given indices. + # + # @see Addressable::Template::MatchData#[] + def values_at(*indexes) + indexes.map { |i| self[i] } + end + + ## + # Returns a String representation of the MatchData's state. + # + # @return [String] The MatchData's state, as a String. + def inspect + sprintf("#<%s:%#0x RESULT:%s>", + self.class.to_s, self.object_id, self.mapping.inspect) + end + + ## + # Dummy method for code expecting a ::MatchData instance + # + # @return [String] An empty string. + def pre_match + "" + end + alias_method :post_match, :pre_match + end + + ## + # Creates a new Addressable::Template object. + # + # @param [#to_str] pattern The URI Template pattern. + # + # @return [Addressable::Template] The initialized Template object. + def initialize(pattern) + if !pattern.respond_to?(:to_str) + raise TypeError, "Can't convert #{pattern.class} into String." + end + @pattern = pattern.to_str.freeze + end + + ## + # @return [String] The Template object's pattern. + attr_reader :pattern + + ## + # Returns a String representation of the Template object's state. + # + # @return [String] The Template object's state, as a String. + def inspect + sprintf("#<%s:%#0x PATTERN:%s>", + self.class.to_s, self.object_id, self.pattern) + end + + ## + # Returns true if the Template objects are equal. This method + # does NOT normalize either Template before doing the comparison. + # + # @param [Object] template The Template to compare. + # + # @return [TrueClass, FalseClass] + # true if the Templates are equivalent, false + # otherwise. + def ==(template) + return false unless template.kind_of?(Template) + return self.pattern == template.pattern + end + + ## + # Addressable::Template makes no distinction between `==` and `eql?`. + # + # @see #== + alias_method :eql?, :== + + ## + # Extracts a mapping from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).extract(uri, ExampleProcessor) + # #=> {"query" => "an example search query"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{second}/" + # ).extract(uri, ExampleProcessor) + # #=> {"first" => "a", "second" => "b/c"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{-list|/|second}/" + # ).extract(uri) + # #=> {"first" => "a", "second" => ["b", "c"]} + def extract(uri, processor=nil) + match_data = self.match(uri, processor) + return (match_data ? match_data.mapping : nil) + end + + ## + # Extracts match data from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # match = Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["query"] + # match.captures + # #=> ["an example search query"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}/{+second}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", "b/c"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}{/second*}/" + # ).match(uri) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", ["b", "c"]] + def match(uri, processor=nil) + uri = Addressable::URI.parse(uri) + mapping = {} + + # First, we need to process the pattern, and extract the values. + expansions, expansion_regexp = + parse_template_pattern(pattern, processor) + + return nil unless uri.to_str.match(expansion_regexp) + unparsed_values = uri.to_str.scan(expansion_regexp).flatten + + if uri.to_str == pattern + return Addressable::Template::MatchData.new(uri, self, mapping) + elsif expansions.size > 0 + index = 0 + expansions.each do |expansion| + _, operator, varlist = *expansion.match(EXPRESSION) + varlist.split(',').each do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + mapping[name] ||= nil + case operator + when nil, '+', '#', '/', '.' + unparsed_value = unparsed_values[index] + name = varspec[VARSPEC, 1] + value = unparsed_value + value = value.split(JOINERS[operator]) if value && modifier == '*' + when ';', '?', '&' + if modifier == '*' + if unparsed_values[index] + value = unparsed_values[index].split(JOINERS[operator]) + value = value.inject({}) do |acc, v| + key, val = v.split('=') + val = "" if val.nil? + acc[key] = val + acc + end + end + else + if (unparsed_values[index]) + name, value = unparsed_values[index].split('=') + value = "" if value.nil? + end + end + end + if processor != nil && processor.respond_to?(:restore) + value = processor.restore(name, value) + end + if processor == nil + if value.is_a?(Hash) + value = value.inject({}){|acc, (k, v)| + acc[Addressable::URI.unencode_component(k)] = + Addressable::URI.unencode_component(v) + acc + } + elsif value.is_a?(Array) + value = value.map{|v| Addressable::URI.unencode_component(v) } + else + value = Addressable::URI.unencode_component(value) + end + end + if !mapping.has_key?(name) || mapping[name].nil? + # Doesn't exist, set to value (even if value is nil) + mapping[name] = value + end + index = index + 1 + end + end + return Addressable::Template::MatchData.new(uri, self, mapping) + else + return nil + end + end + + ## + # Expands a URI template into another URI template. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::Template] The partially expanded URI template. + # + # @example + # Addressable::Template.new( + # "http://example.com/{one}/{two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/1/{two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/?one=1{&two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two,three}/" + # ).partial_expand({"one" => "1", "three" => 3}).pattern + # #=> "http://example.com/?one=1{&two}&three=3" + def partial_expand(mapping, processor=nil) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_partial_capture(mapping, capture, processor) + end + return Addressable::Template.new(result) + end + + ## + # Expands a URI template into a full URI. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::URI] The expanded URI template. + # + # @example + # class ExampleProcessor + # def self.validate(name, value) + # return !!(value =~ /^[\w ]+$/) if name == "query" + # return true + # end + # + # def self.transform(name, value) + # return value.gsub(/ /, "+") if name == "query" + # return value + # end + # end + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"}, + # ExampleProcessor + # ).to_str + # #=> "http://example.com/search/an+example+search+query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"} + # ).to_str + # #=> "http://example.com/search/an%20example%20search%20query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "bogus!"}, + # ExampleProcessor + # ).to_str + # #=> Addressable::Template::InvalidTemplateValueError + def expand(mapping, processor=nil) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_capture(mapping, capture, processor) + end + return Addressable::URI.parse(result) + end + + ## + # Returns an Array of variables used within the template pattern. + # The variables are listed in the Array in the order they appear within + # the pattern. Multiple occurrences of a variable within a pattern are + # not represented in this Array. + # + # @return [Array] The variables present in the template's pattern. + def variables + @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq + end + alias_method :keys, :variables + + ## + # Returns a mapping of variables to their default values specified + # in the template. Variables without defaults are not returned. + # + # @return [Hash] Mapping of template variables to their defaults + def variable_defaults + @variable_defaults ||= + Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten] + end + + private + def ordered_variable_defaults + @ordered_variable_defaults ||= ( + expansions, _ = parse_template_pattern(pattern) + expansions.map do |capture| + _, _, varlist = *capture.match(EXPRESSION) + varlist.split(',').map do |varspec| + varspec[VARSPEC, 1] + end + end.flatten + ) + end + + + ## + # Loops through each capture and expands any values available in mapping + # + # @param [Hash] mapping + # Set of keys to expand + # @param [String] capture + # The expression to expand + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_partial_capture(mapping, capture, processor = nil) + _, operator, varlist = *capture.match(EXPRESSION) + is_first = true + varlist.split(',').inject('') do |acc, varspec| + _, name, _ = *varspec.match(VARSPEC) + value = mapping[name] + if value + operator = '&' if !is_first && operator == '?' + acc << transform_capture(mapping, "{#{operator}#{varspec}}", processor) + else + operator = '&' if !is_first && operator == '?' + acc << "{#{operator}#{varspec}}" + end + is_first = false + acc + end + end + + ## + # Transforms a mapped value so that values can be substituted into the + # template. + # + # @param [Hash] mapping The mapping to replace captures + # @param [String] capture + # The expression to replace + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_capture(mapping, capture, processor=nil) + _, operator, varlist = *capture.match(EXPRESSION) + return_value = varlist.split(',').inject([]) do |acc, varspec| + _, name, modifier = *varspec.match(VARSPEC) + value = mapping[name] + unless value == nil || value == {} + allow_reserved = %w(+ #).include?(operator) + # Common primitives where the .to_s output is well-defined + if Numeric === value || Symbol === value || + value == true || value == false + value = value.to_s + end + length = modifier.gsub(':', '').to_i if modifier =~ /^:\d+/ + + unless (Hash === value) || + value.respond_to?(:to_ary) || value.respond_to?(:to_str) + raise TypeError, + "Can't convert #{value.class} into String or Array." + end + + value = normalize_value(value) + + if processor == nil || !processor.respond_to?(:transform) + # Handle percent escaping + if allow_reserved + encode_map = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + else + encode_map = Addressable::URI::CharacterClasses::UNRESERVED + end + if value.kind_of?(Array) + transformed_value = value.map do |val| + if length + Addressable::URI.encode_component(val[0...length], encode_map) + else + Addressable::URI.encode_component(val, encode_map) + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + elsif value.kind_of?(Hash) + transformed_value = value.map do |key, val| + if modifier == "*" + "#{ + Addressable::URI.encode_component( key, encode_map) + }=#{ + Addressable::URI.encode_component( val, encode_map) + }" + else + "#{ + Addressable::URI.encode_component( key, encode_map) + },#{ + Addressable::URI.encode_component( val, encode_map) + }" + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + else + if length + transformed_value = Addressable::URI.encode_component( + value[0...length], encode_map) + else + transformed_value = Addressable::URI.encode_component( + value, encode_map) + end + end + end + + # Process, if we've got a processor + if processor != nil + if processor.respond_to?(:validate) + if !processor.validate(name, value) + display_value = value.kind_of?(Array) ? value.inspect : value + raise InvalidTemplateValueError, + "#{name}=#{display_value} is an invalid template value." + end + end + if processor.respond_to?(:transform) + transformed_value = processor.transform(name, value) + transformed_value = normalize_value(transformed_value) + end + end + acc << [name, transformed_value] + end + acc + end + return "" if return_value.empty? + join_values(operator, return_value) + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [String, Nil] operator One of the operators from the set + # (?,&,+,#,;,/,.), or nil if there wasn't one. + # @param [Array] return_value + # The set of return values (as [variable_name, value] tuples) that will + # be joined together. + # + # @return [String] The transformed mapped value + def join_values(operator, return_value) + leader = LEADERS.fetch(operator, '') + joiner = JOINERS.fetch(operator, ',') + case operator + when '&', '?' + leader + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + v.join(joiner) + elsif v.is_a?(Array) + v.map{|inner_value| "#{k}=#{inner_value}"}.join(joiner) + else + "#{k}=#{v}" + end + }.join(joiner) + when ';' + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + ';' + v.join(";") + elsif v.is_a?(Array) + ';' + v.map{|inner_value| "#{k}=#{inner_value}"}.join(";") + else + v && v != '' ? ";#{k}=#{v}" : ";#{k}" + end + }.join + else + leader + return_value.map{|k,v| v}.join(joiner) + end + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [Hash, Array, String] value + # Normalizes keys and values with IDNA#unicode_normalize_kc + # + # @return [Hash, Array, String] The normalized values + def normalize_value(value) + unless value.is_a?(Hash) + value = value.respond_to?(:to_ary) ? value.to_ary : value.to_str + end + + # Handle unicode normalization + if value.kind_of?(Array) + value.map! { |val| Addressable::IDNA.unicode_normalize_kc(val) } + elsif value.kind_of?(Hash) + value = value.inject({}) { |acc, (k, v)| + acc[Addressable::IDNA.unicode_normalize_kc(k)] = + Addressable::IDNA.unicode_normalize_kc(v) + acc + } + else + value = Addressable::IDNA.unicode_normalize_kc(value) + end + value + end + + ## + # Generates a hash with string keys + # + # @param [Hash] mapping A mapping hash to normalize + # + # @return [Hash] + # A hash with stringified keys + def normalize_keys(mapping) + return mapping.inject({}) do |accu, pair| + name, value = pair + if Symbol === name + name = name.to_s + elsif name.respond_to?(:to_str) + name = name.to_str + else + raise TypeError, + "Can't convert #{name.class} into String." + end + accu[name] = value + accu + end + end + + ## + # Generates the Regexp that parses a template pattern. + # + # @param [String] pattern The URI template pattern. + # @param [#match] processor The template processor to use. + # + # @return [Regexp] + # A regular expression which may be used to parse a template pattern. + def parse_template_pattern(pattern, processor=nil) + # Escape the pattern. The two gsubs restore the escaped curly braces + # back to their original form. Basically, escape everything that isn't + # within an expansion. + escaped_pattern = Regexp.escape( + pattern + ).gsub(/\\\{(.*?)\\\}/) do |escaped| + escaped.gsub(/\\(.)/, "\\1") + end + + expansions = [] + + # Create a regular expression that captures the values of the + # variables in the URI. + regexp_string = escaped_pattern.gsub( EXPRESSION ) do |expansion| + + expansions << expansion + _, operator, varlist = *expansion.match(EXPRESSION) + leader = Regexp.escape(LEADERS.fetch(operator, '')) + joiner = Regexp.escape(JOINERS.fetch(operator, ',')) + combined = varlist.split(',').map do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + + result = processor && processor.respond_to?(:match) ? processor.match(name) : nil + if result + "(#{ result })" + else + group = case operator + when '+' + "#{ RESERVED }*?" + when '#' + "#{ RESERVED }*?" + when '/' + "#{ UNRESERVED }*?" + when '.' + "#{ UNRESERVED.gsub('\.', '') }*?" + when ';' + "#{ UNRESERVED }*=?#{ UNRESERVED }*?" + when '?' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + when '&' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + else + "#{ UNRESERVED }*?" + end + if modifier == '*' + "(#{group}(?:#{joiner}?#{group})*)?" + else + "(#{group})?" + end + end + end.join("#{joiner}?") + "(?:|#{leader}#{combined})" + end + + # Ensure that the regular expression matches the whole URI. + regexp_string = "^#{regexp_string}$" + return expansions, Regexp.new(regexp_string) + end + + end +end diff --git a/.gems/gems/addressable-2.3.6/lib/addressable/uri.rb b/.gems/gems/addressable-2.3.6/lib/addressable/uri.rb new file mode 100644 index 0000000..e7ddc9f --- /dev/null +++ b/.gems/gems/addressable-2.3.6/lib/addressable/uri.rb @@ -0,0 +1,2351 @@ +# encoding:utf-8 +#-- +# Copyright (C) 2006-2013 Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/idna" + +## +# Addressable is a library for processing links and URIs. +module Addressable + ## + # This is an implementation of a URI parser based on + # RFC 3986, + # RFC 3987. + class URI + ## + # Raised if something other than a uri is supplied. + class InvalidURIError < StandardError + end + + ## + # Container for the character classes specified in + # RFC 3986. + module CharacterClasses + ALPHA = "a-zA-Z" + DIGIT = "0-9" + GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@" + SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=" + RESERVED = GEN_DELIMS + SUB_DELIMS + UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~" + PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@" + SCHEME = ALPHA + DIGIT + "\\-\\+\\." + AUTHORITY = PCHAR + PATH = PCHAR + "\\/" + QUERY = PCHAR + "\\/\\?" + FRAGMENT = PCHAR + "\\/\\?" + end + + SLASH = '/' + EMPTY_STR = '' + + URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ + + PORT_MAPPING = { + "http" => 80, + "https" => 443, + "ftp" => 21, + "tftp" => 69, + "sftp" => 22, + "ssh" => 22, + "svn+ssh" => 22, + "telnet" => 23, + "nntp" => 119, + "gopher" => 70, + "wais" => 210, + "ldap" => 389, + "prospero" => 1525 + } + + ## + # Returns a URI object based on the parsed string. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # + # @return [Addressable::URI] The parsed URI. + def self.parse(uri) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + # Otherwise, convert to a String + begin + uri = uri.to_str + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{uri.class} into String." + end if not uri.is_a? String + + # This Regexp supplied as an example in RFC 3986, and it works great. + scan = uri.scan(URIREGEX) + fragments = scan[0] + scheme = fragments[1] + authority = fragments[3] + path = fragments[4] + query = fragments[6] + fragment = fragments[8] + user = nil + password = nil + host = nil + port = nil + if authority != nil + # The Regexp above doesn't split apart the authority. + userinfo = authority[/^([^\[\]]*)@/, 1] + if userinfo != nil + user = userinfo.strip[/^([^:]*):?/, 1] + password = userinfo.strip[/:(.*)$/, 1] + end + host = authority.gsub( + /^([^\[\]]*)@/, EMPTY_STR + ).gsub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + port = authority[/:([^:@\[\]]*?)$/, 1] + end + if port == EMPTY_STR + port = nil + end + + return new( + :scheme => scheme, + :user => user, + :password => password, + :host => host, + :port => port, + :path => path, + :query => query, + :fragment => fragment + ) + end + + ## + # Converts an input to a URI. The input does not have to be a valid + # URI — the method will use heuristics to guess what URI was intended. + # This is not standards-compliant, merely user-friendly. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # @param [Hash] hints + # A Hash of hints to the heuristic parser. + # Defaults to {:scheme => "http"}. + # + # @return [Addressable::URI] The parsed URI. + def self.heuristic_parse(uri, hints={}) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + # Otherwise, convert to a String + uri = uri.to_str.dup + hints = { + :scheme => "http" + }.merge(hints) + case uri + when /^http:\/+/ + uri.gsub!(/^http:\/+/, "http://") + when /^https:\/+/ + uri.gsub!(/^https:\/+/, "https://") + when /^feed:\/+http:\/+/ + uri.gsub!(/^feed:\/+http:\/+/, "feed:http://") + when /^feed:\/+/ + uri.gsub!(/^feed:\/+/, "feed://") + when /^file:\/+/ + uri.gsub!(/^file:\/+/, "file:///") + when /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ + uri.gsub!(/^/, hints[:scheme] + "://") + end + parsed = self.parse(uri) + if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/ + parsed = self.parse(hints[:scheme] + "://" + uri) + end + if parsed.path.include?(".") + new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1] + if new_host + parsed.defer_validation do + new_path = parsed.path.gsub( + Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR) + parsed.host = new_host + parsed.path = new_path + parsed.scheme = hints[:scheme] unless parsed.scheme + end + end + end + return parsed + end + + ## + # Converts a path to a file scheme URI. If the path supplied is + # relative, it will be returned as a relative URI. If the path supplied + # is actually a non-file URI, it will parse the URI as if it had been + # parsed with Addressable::URI.parse. Handles all of the + # various Microsoft-specific formats for specifying paths. + # + # @param [String, Addressable::URI, #to_str] path + # Typically a String path to a file or directory, but + # will return a sensible return value if an absolute URI is supplied + # instead. + # + # @return [Addressable::URI] + # The parsed file scheme URI or the original URI if some other URI + # scheme was provided. + # + # @example + # base = Addressable::URI.convert_path("/absolute/path/") + # uri = Addressable::URI.convert_path("relative/path") + # (base + uri).to_s + # #=> "file:///absolute/path/relative/path" + # + # Addressable::URI.convert_path( + # "c:\\windows\\My Documents 100%20\\foo.txt" + # ).to_s + # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt" + # + # Addressable::URI.convert_path("http://example.com/").to_s + # #=> "http://example.com/" + def self.convert_path(path) + # If we were given nil, return nil. + return nil unless path + # If a URI object is passed, just return itself. + return path if path.kind_of?(self) + if !path.respond_to?(:to_str) + raise TypeError, "Can't convert #{path.class} into String." + end + # Otherwise, convert to a String + path = path.to_str.strip + + path.gsub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/ + path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/ + uri = self.parse(path) + + if uri.scheme == nil + # Adjust windows-style uris + uri.path.gsub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do + "/#{$1.downcase}:/" + end + uri.path.gsub!(/\\/, SLASH) + if File.exists?(uri.path) && + File.stat(uri.path).directory? + uri.path.gsub!(/\/$/, EMPTY_STR) + uri.path = uri.path + '/' + end + + # If the path is absolute, set the scheme and host. + if uri.path =~ /^\// + uri.scheme = "file" + uri.host = EMPTY_STR + end + uri.normalize! + end + + return uri + end + + ## + # Joins several URIs together. + # + # @param [String, Addressable::URI, #to_str] *uris + # The URIs to join. + # + # @return [Addressable::URI] The joined URI. + # + # @example + # base = "http://example.com/" + # uri = Addressable::URI.parse("relative/path") + # Addressable::URI.join(base, uri) + # #=> # + def self.join(*uris) + uri_objects = uris.collect do |uri| + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + uri.kind_of?(self) ? uri : self.parse(uri.to_str) + end + result = uri_objects.shift.dup + for uri in uri_objects + result.join!(uri) + end + return result + end + + ## + # Percent encodes a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' through + # '9' to be percent encoded. If a Regexp is passed, the + # value /[^b-zB-Z0-9]/ would have the same effect. A set of + # useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [Regexp] upcase_encoded + # A string of characters that may already be percent encoded, and whose + # encodings should be upcased. This allows normalization of percent + # encodings for characters not included in the + # character_class. + # + # @return [String] The encoded component. + # + # @example + # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9") + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/) + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component( + # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + def self.encode_component(component, character_class= + CharacterClasses::RESERVED + CharacterClasses::UNRESERVED, + upcase_encoded='') + return nil if component.nil? + + begin + if component.kind_of?(Symbol) || + component.kind_of?(Numeric) || + component.kind_of?(TrueClass) || + component.kind_of?(FalseClass) + component = component.to_s + else + component = component.to_str + end + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + character_class = /[^#{character_class}]/ + end + if component.respond_to?(:force_encoding) + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + end + # Avoiding gsub! because there are edge cases with frozen strings + component = component.gsub(character_class) do |sequence| + (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join + end + if upcase_encoded.length > 0 + component = component.gsub(/%(#{upcase_encoded.chars.map do |char| + char.unpack('C*').map { |c| '%02x' % c }.join + end.join('|')})/i) { |s| s.upcase } + end + return component + end + + class << self + alias_method :encode_component, :encode_component + end + + ## + # Unencodes any percent encoded characters within a URI component. + # This method may be used for unencoding either components or full URIs, + # however, it is recommended to use the unencode_component + # alias when unencoding components. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI or component to unencode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @param [String] leave_encoded + # A string of characters to leave encoded. If a percent encoded character + # in this list is encountered then it will remain percent encoded. + # + # @return [String, Addressable::URI] + # The unencoded component or URI. + # The return type is determined by the return_type + # parameter. + def self.unencode(uri, return_type=String, leave_encoded='') + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri = uri.dup + # Seriously, only use UTF-8. I'm really not kidding! + uri.force_encoding("utf-8") if uri.respond_to?(:force_encoding) + leave_encoded.force_encoding("utf-8") if leave_encoded.respond_to?(:force_encoding) + result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence| + c = sequence[1..3].to_i(16).chr + c.force_encoding("utf-8") if c.respond_to?(:force_encoding) + leave_encoded.include?(c) ? sequence : c + end + result.force_encoding("utf-8") if result.respond_to?(:force_encoding) + if return_type == String + return result + elsif return_type == ::Addressable::URI + return ::Addressable::URI.parse(result) + end + end + + class << self + alias_method :unescape, :unencode + alias_method :unencode_component, :unencode + alias_method :unescape_component, :unencode + end + + + ## + # Normalizes the encoding of a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' + # through '9' to be percent encoded. If a Regexp is passed, + # the value /[^b-zB-Z0-9]/ would have the same effect. A + # set of useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [String] leave_encoded + # When character_class is a String then + # leave_encoded is a string of characters that should remain + # percent encoded while normalizing the component; if they appear percent + # encoded in the original component, then they will be upcased ("%2f" + # normalized to "%2F") but otherwise left alone. + # + # @return [String] The normalized component. + # + # @example + # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z") + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", /[^b-zB-Z]/ + # ) + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", + # Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + # Addressable::URI.normalize_component( + # "one%20two%2fthree%26four", + # "0-9a-zA-Z &/", + # "/" + # ) + # => "one two%2Fthree&four" + def self.normalize_component(component, character_class= + CharacterClasses::RESERVED + CharacterClasses::UNRESERVED, + leave_encoded='') + return nil if component.nil? + + begin + component = component.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + leave_re = if leave_encoded.length > 0 + character_class = "#{character_class}%" unless character_class.include?('%') + + "|%(?!#{leave_encoded.chars.map do |char| + seq = char.unpack('C*').map { |c| '%02x' % c }.join + [seq.upcase, seq.downcase] + end.flatten.join('|')})" + end + + character_class = /[^#{character_class}]#{leave_re}/ + end + if component.respond_to?(:force_encoding) + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + end + unencoded = self.unencode_component(component, String, leave_encoded) + begin + encoded = self.encode_component( + Addressable::IDNA.unicode_normalize_kc(unencoded), + character_class, + leave_encoded + ) + rescue ArgumentError + encoded = self.encode_component(unencoded) + end + if encoded.respond_to?(:force_encoding) + encoded.force_encoding(Encoding::UTF_8) + end + return encoded + end + + ## + # Percent encodes any special characters in the URI. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.encode(uri, return_type=String) + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(uri_object.scheme, + Addressable::URI::CharacterClasses::SCHEME), + :authority => self.encode_component(uri_object.authority, + Addressable::URI::CharacterClasses::AUTHORITY), + :path => self.encode_component(uri_object.path, + Addressable::URI::CharacterClasses::PATH), + :query => self.encode_component(uri_object.query, + Addressable::URI::CharacterClasses::QUERY), + :fragment => self.encode_component(uri_object.fragment, + Addressable::URI::CharacterClasses::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + class << self + alias_method :escape, :encode + end + + ## + # Normalizes the encoding of a URI. Characters within a hostname are + # not percent encoded to allow for internationalized domain names. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.normalized_encode(uri, return_type=String) + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + components = { + :scheme => self.unencode_component(uri_object.scheme), + :user => self.unencode_component(uri_object.user), + :password => self.unencode_component(uri_object.password), + :host => self.unencode_component(uri_object.host), + :port => (uri_object.port.nil? ? nil : uri_object.port.to_s), + :path => self.unencode_component(uri_object.path), + :query => self.unencode_component(uri_object.query), + :fragment => self.unencode_component(uri_object.fragment) + } + components.each do |key, value| + if value != nil + begin + components[key] = + Addressable::IDNA.unicode_normalize_kc(value.to_str) + rescue ArgumentError + # Likely a malformed UTF-8 character, skip unicode normalization + components[key] = value.to_str + end + end + end + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(components[:scheme], + Addressable::URI::CharacterClasses::SCHEME), + :user => self.encode_component(components[:user], + Addressable::URI::CharacterClasses::UNRESERVED), + :password => self.encode_component(components[:password], + Addressable::URI::CharacterClasses::UNRESERVED), + :host => components[:host], + :port => components[:port], + :path => self.encode_component(components[:path], + Addressable::URI::CharacterClasses::PATH), + :query => self.encode_component(components[:query], + Addressable::URI::CharacterClasses::QUERY), + :fragment => self.encode_component(components[:fragment], + Addressable::URI::CharacterClasses::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + ## + # Encodes a set of key/value pairs according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [#to_hash, #to_ary] form_values + # The form values to encode. + # + # @param [TrueClass, FalseClass] sort + # Sort the key/value pairs prior to encoding. + # Defaults to false. + # + # @return [String] + # The encoded value. + def self.form_encode(form_values, sort=false) + if form_values.respond_to?(:to_hash) + form_values = form_values.to_hash.to_a + elsif form_values.respond_to?(:to_ary) + form_values = form_values.to_ary + else + raise TypeError, "Can't convert #{form_values.class} into Array." + end + + form_values = form_values.inject([]) do |accu, (key, value)| + if value.kind_of?(Array) + value.each do |v| + accu << [key.to_s, v.to_s] + end + else + accu << [key.to_s, value.to_s] + end + accu + end + + if sort + # Useful for OAuth and optimizing caching systems + form_values = form_values.sort + end + escaped_form_values = form_values.map do |(key, value)| + # Line breaks are CRLF pairs + [ + self.encode_component( + key.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClasses::UNRESERVED + ).gsub("%20", "+"), + self.encode_component( + value.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClasses::UNRESERVED + ).gsub("%20", "+") + ] + end + return (escaped_form_values.map do |(key, value)| + "#{key}=#{value}" + end).join("&") + end + + ## + # Decodes a String according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [String, #to_str] encoded_value + # The form values to decode. + # + # @return [Array] + # The decoded values. + # This is not a Hash because of the possibility for + # duplicate keys. + def self.form_unencode(encoded_value) + if !encoded_value.respond_to?(:to_str) + raise TypeError, "Can't convert #{encoded_value.class} into String." + end + encoded_value = encoded_value.to_str + split_values = encoded_value.split("&").map do |pair| + pair.split("=", 2) + end + return split_values.map do |(key, value)| + [ + key ? self.unencode_component( + key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil, + value ? (self.unencode_component( + value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil + ] + end + end + + ## + # Creates a new uri object from component parts. + # + # @option [String, #to_str] scheme The scheme component. + # @option [String, #to_str] user The user component. + # @option [String, #to_str] password The password component. + # @option [String, #to_str] userinfo + # The userinfo component. If this is supplied, the user and password + # components must be omitted. + # @option [String, #to_str] host The host component. + # @option [String, #to_str] port The port component. + # @option [String, #to_str] authority + # The authority component. If this is supplied, the user, password, + # userinfo, host, and port components must be omitted. + # @option [String, #to_str] path The path component. + # @option [String, #to_str] query The query component. + # @option [String, #to_str] fragment The fragment component. + # + # @return [Addressable::URI] The constructed URI object. + def initialize(options={}) + if options.has_key?(:authority) + if (options.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if options.has_key?(:userinfo) + if (options.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + self.defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + self.scheme = options[:scheme] if options[:scheme] + self.user = options[:user] if options[:user] + self.password = options[:password] if options[:password] + self.userinfo = options[:userinfo] if options[:userinfo] + self.host = options[:host] if options[:host] + self.port = options[:port] if options[:port] + self.authority = options[:authority] if options[:authority] + self.path = options[:path] if options[:path] + self.query = options[:query] if options[:query] + self.query_values = options[:query_values] if options[:query_values] + self.fragment = options[:fragment] if options[:fragment] + end + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.normalized_scheme + self.normalized_user + self.normalized_password + self.normalized_userinfo + self.normalized_host + self.normalized_port + self.normalized_authority + self.normalized_site + self.normalized_path + self.normalized_query + self.normalized_fragment + self.hash + super + end + + ## + # The scheme component for this URI. + # + # @return [String] The scheme component. + def scheme + return instance_variable_defined?(:@scheme) ? @scheme : nil + end + + ## + # The scheme component for this URI, normalized. + # + # @return [String] The scheme component, normalized. + def normalized_scheme + self.scheme && @normalized_scheme ||= (begin + if self.scheme =~ /^\s*ssh\+svn\s*$/i + "svn+ssh" + else + Addressable::URI.normalize_component( + self.scheme.strip.downcase, + Addressable::URI::CharacterClasses::SCHEME + ) + end + end) + end + + ## + # Sets the scheme component for this URI. + # + # @param [String, #to_str] new_scheme The new scheme component. + def scheme=(new_scheme) + if new_scheme && !new_scheme.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_scheme.class} into String." + elsif new_scheme + new_scheme = new_scheme.to_str + end + if new_scheme && new_scheme !~ /[a-z][a-z0-9\.\+\-]*/i + raise InvalidURIError, "Invalid scheme format." + end + @scheme = new_scheme + @scheme = nil if @scheme.to_s.strip.empty? + + # Reset dependant values + @normalized_scheme = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The user component for this URI. + # + # @return [String] The user component. + def user + return instance_variable_defined?(:@user) ? @user : nil + end + + ## + # The user component for this URI, normalized. + # + # @return [String] The user component, normalized. + def normalized_user + self.user && @normalized_user ||= (begin + if normalized_scheme =~ /https?/ && self.user.strip.empty? && + (!self.password || self.password.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.user.strip, + Addressable::URI::CharacterClasses::UNRESERVED + ) + end + end) + end + + ## + # Sets the user component for this URI. + # + # @param [String, #to_str] new_user The new user component. + def user=(new_user) + if new_user && !new_user.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_user.class} into String." + end + @user = new_user ? new_user.to_str : nil + + # You can't have a nil user with a non-nil password + if password != nil + @user = EMPTY_STR if @user.nil? + end + + # Reset dependant values + @userinfo = nil + @normalized_userinfo = nil + @authority = nil + @normalized_user = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The password component for this URI. + # + # @return [String] The password component. + def password + return instance_variable_defined?(:@password) ? @password : nil + end + + ## + # The password component for this URI, normalized. + # + # @return [String] The password component, normalized. + def normalized_password + self.password && @normalized_password ||= (begin + if self.normalized_scheme =~ /https?/ && self.password.strip.empty? && + (!self.user || self.user.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.password.strip, + Addressable::URI::CharacterClasses::UNRESERVED + ) + end + end) + end + + ## + # Sets the password component for this URI. + # + # @param [String, #to_str] new_password The new password component. + def password=(new_password) + if new_password && !new_password.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_password.class} into String." + end + @password = new_password ? new_password.to_str : nil + + # You can't have a nil user with a non-nil password + @password ||= nil + @user ||= nil + if @password != nil + @user = EMPTY_STR if @user.nil? + end + + # Reset dependant values + @userinfo = nil + @normalized_userinfo = nil + @authority = nil + @normalized_password = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The userinfo component for this URI. + # Combines the user and password components. + # + # @return [String] The userinfo component. + def userinfo + current_user = self.user + current_password = self.password + (current_user || current_password) && @userinfo ||= (begin + if current_user && current_password + "#{current_user}:#{current_password}" + elsif current_user && !current_password + "#{current_user}" + end + end) + end + + ## + # The userinfo component for this URI, normalized. + # + # @return [String] The userinfo component, normalized. + def normalized_userinfo + self.userinfo && @normalized_userinfo ||= (begin + current_user = self.normalized_user + current_password = self.normalized_password + if !current_user && !current_password + nil + elsif current_user && current_password + "#{current_user}:#{current_password}" + elsif current_user && !current_password + "#{current_user}" + end + end) + end + + ## + # Sets the userinfo component for this URI. + # + # @param [String, #to_str] new_userinfo The new userinfo component. + def userinfo=(new_userinfo) + if new_userinfo && !new_userinfo.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_userinfo.class} into String." + end + new_user, new_password = if new_userinfo + [ + new_userinfo.to_str.strip[/^(.*):/, 1], + new_userinfo.to_str.strip[/:(.*)$/, 1] + ] + else + [nil, nil] + end + + # Password assigned first to ensure validity in case of nil + self.password = new_password + self.user = new_user + + # Reset dependant values + @authority = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The host component for this URI. + # + # @return [String] The host component. + def host + return instance_variable_defined?(:@host) ? @host : nil + end + + ## + # The host component for this URI, normalized. + # + # @return [String] The host component, normalized. + def normalized_host + self.host && @normalized_host ||= (begin + if !self.host.strip.empty? + result = ::Addressable::IDNA.to_ascii( + URI.unencode_component(self.host.strip.downcase) + ) + if result =~ /[^\.]\.$/ + # Single trailing dots are unnecessary. + result = result[0...-1] + end + result + else + EMPTY_STR + end + end) + end + + ## + # Sets the host component for this URI. + # + # @param [String, #to_str] new_host The new host component. + def host=(new_host) + if new_host && !new_host.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_host.class} into String." + end + @host = new_host ? new_host.to_str : nil + + unreserved = CharacterClasses::UNRESERVED + sub_delims = CharacterClasses::SUB_DELIMS + if @host != nil && (@host =~ /[<>{}\/\?\#\@]/ || + (@host[/^\[(.*)\]$/, 1] != nil && @host[/^\[(.*)\]$/, 1] !~ + Regexp.new("^[#{unreserved}#{sub_delims}:]*$"))) + raise InvalidURIError, "Invalid character in host: '#{@host.to_s}'" + end + + # Reset dependant values + @authority = nil + @normalized_host = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # This method is same as URI::Generic#host except + # brackets for IPv6 (and 'IPvFuture') addresses are removed. + # + # @see Addressable::URI#host + # + # @return [String] The hostname for this URI. + def hostname + v = self.host + /\A\[(.*)\]\z/ =~ v ? $1 : v + end + + ## + # This method is same as URI::Generic#host= except + # the argument can be a bare IPv6 address (or 'IPvFuture'). + # + # @see Addressable::URI#host= + # + # @param [String, #to_str] new_hostname The new hostname for this URI. + def hostname=(new_hostname) + if new_hostname && !new_hostname.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_hostname.class} into String." + end + v = new_hostname ? new_hostname.to_str : nil + v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v + self.host = v + end + + ## + # The authority component for this URI. + # Combines the user, password, host, and port components. + # + # @return [String] The authority component. + def authority + self.host && @authority ||= (begin + authority = "" + if self.userinfo != nil + authority << "#{self.userinfo}@" + end + authority << self.host + if self.port != nil + authority << ":#{self.port}" + end + authority + end) + end + + ## + # The authority component for this URI, normalized. + # + # @return [String] The authority component, normalized. + def normalized_authority + self.authority && @normalized_authority ||= (begin + authority = "" + if self.normalized_userinfo != nil + authority << "#{self.normalized_userinfo}@" + end + authority << self.normalized_host + if self.normalized_port != nil + authority << ":#{self.normalized_port}" + end + authority + end) + end + + ## + # Sets the authority component for this URI. + # + # @param [String, #to_str] new_authority The new authority component. + def authority=(new_authority) + if new_authority + if !new_authority.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_authority.class} into String." + end + new_authority = new_authority.to_str + new_userinfo = new_authority[/^([^\[\]]*)@/, 1] + if new_userinfo + new_user = new_userinfo.strip[/^([^:]*):?/, 1] + new_password = new_userinfo.strip[/:(.*)$/, 1] + end + new_host = new_authority.gsub( + /^([^\[\]]*)@/, EMPTY_STR + ).gsub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + new_port = + new_authority[/:([^:@\[\]]*?)$/, 1] + end + + # Password assigned first to ensure validity in case of nil + self.password = defined?(new_password) ? new_password : nil + self.user = defined?(new_user) ? new_user : nil + self.host = defined?(new_host) ? new_host : nil + self.port = defined?(new_port) ? new_port : nil + + # Reset dependant values + @userinfo = nil + @normalized_userinfo = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. + # + # @return [String] The serialized origin. + def origin + return (if self.scheme && self.authority + if self.normalized_port + ( + "#{self.normalized_scheme}://#{self.normalized_host}" + + ":#{self.normalized_port}" + ) + else + "#{self.normalized_scheme}://#{self.normalized_host}" + end + else + "null" + end) + end + + # Returns an array of known ip-based schemes. These schemes typically + # use a similar URI form: + # //:@:/ + def self.ip_based_schemes + return self.port_mapping.keys + end + + # Returns a hash of common IP-based schemes and their default port + # numbers. Adding new schemes to this hash, as necessary, will allow + # for better URI normalization. + def self.port_mapping + PORT_MAPPING + end + + ## + # The port component for this URI. + # This is the port number actually given in the URI. This does not + # infer port numbers from default values. + # + # @return [Integer] The port component. + def port + return instance_variable_defined?(:@port) ? @port : nil + end + + ## + # The port component for this URI, normalized. + # + # @return [Integer] The port component, normalized. + def normalized_port + if URI.port_mapping[self.normalized_scheme] == self.port + nil + else + self.port + end + end + + ## + # Sets the port component for this URI. + # + # @param [String, Integer, #to_s] new_port The new port component. + def port=(new_port) + if new_port != nil && new_port.respond_to?(:to_str) + new_port = Addressable::URI.unencode_component(new_port.to_str) + end + if new_port != nil && !(new_port.to_s =~ /^\d+$/) + raise InvalidURIError, + "Invalid port number: #{new_port.inspect}" + end + + @port = new_port.to_s.to_i + @port = nil if @port == 0 + + # Reset dependant values + @authority = nil + @normalized_port = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The inferred port component for this URI. + # This method will normalize to the default port for the URI's scheme if + # the port isn't explicitly specified in the URI. + # + # @return [Integer] The inferred port component. + def inferred_port + if self.port.to_i == 0 + self.default_port + else + self.port.to_i + end + end + + ## + # The default port for this URI's scheme. + # This method will always returns the default port for the URI's scheme + # regardless of the presence of an explicit port in the URI. + # + # @return [Integer] The default port. + def default_port + URI.port_mapping[self.scheme.strip.downcase] if self.scheme + end + + ## + # The combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The components that identify a site. + def site + (self.scheme || self.authority) && @site ||= (begin + site_string = "" + site_string << "#{self.scheme}:" if self.scheme != nil + site_string << "//#{self.authority}" if self.authority != nil + site_string + end) + end + + ## + # The normalized combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The normalized components that identify a site. + def normalized_site + self.site && @normalized_site ||= (begin + site_string = "" + if self.normalized_scheme != nil + site_string << "#{self.normalized_scheme}:" + end + if self.normalized_authority != nil + site_string << "//#{self.normalized_authority}" + end + site_string + end) + end + + ## + # Sets the site value for this URI. + # + # @param [String, #to_str] new_site The new site value. + def site=(new_site) + if new_site + if !new_site.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_site.class} into String." + end + new_site = new_site.to_str + # These two regular expressions derived from the primary parsing + # expression + self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1] + self.authority = new_site[ + /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1 + ] + else + self.scheme = nil + self.authority = nil + end + end + + ## + # The path component for this URI. + # + # @return [String] The path component. + def path + return instance_variable_defined?(:@path) ? @path : EMPTY_STR + end + + NORMPATH = /^(?!\/)[^\/:]*:.*$/ + ## + # The path component for this URI, normalized. + # + # @return [String] The path component, normalized. + def normalized_path + @normalized_path ||= (begin + path = self.path.to_s + if self.scheme == nil && path =~ NORMPATH + # Relative paths with colons in the first segment are ambiguous. + path = path.sub(":", "%2F") + end + # String#split(delimeter, -1) uses the more strict splitting behavior + # found by default in Python. + result = (path.strip.split(SLASH, -1).map do |segment| + Addressable::URI.normalize_component( + segment, + Addressable::URI::CharacterClasses::PCHAR + ) + end).join(SLASH) + + result = URI.normalize_path(result) + if result.empty? && + ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme) + result = SLASH + end + result + end) + end + + ## + # Sets the path component for this URI. + # + # @param [String, #to_str] new_path The new path component. + def path=(new_path) + if new_path && !new_path.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_path.class} into String." + end + @path = (new_path || EMPTY_STR).to_str + if !@path.empty? && @path[0..0] != SLASH && host != nil + @path = "/#{@path}" + end + + # Reset dependant values + @normalized_path = nil + @uri_string = nil + @hash = nil + end + + ## + # The basename, if any, of the file in the path component. + # + # @return [String] The path's basename. + def basename + # Path cannot be nil + return File.basename(self.path).gsub(/;[^\/]*$/, EMPTY_STR) + end + + ## + # The extname, if any, of the file in the path component. + # Empty string if there is no extension. + # + # @return [String] The path's extname. + def extname + return nil unless self.path + return File.extname(self.basename) + end + + ## + # The query component for this URI. + # + # @return [String] The query component. + def query + return instance_variable_defined?(:@query) ? @query : nil + end + + ## + # The query component for this URI, normalized. + # + # @return [String] The query component, normalized. + def normalized_query(*flags) + modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup + # Make sure possible key-value pair delimiters are escaped. + modified_query_class.sub!("\\&", "").sub!("\\;", "") + pairs = (self.query || "").split("&", -1) + pairs.sort! if flags.include?(:sorted) + component = (pairs.map do |pair| + Addressable::URI.normalize_component(pair, modified_query_class, "+") + end).join("&") + component == "" ? nil : component + end + + ## + # Sets the query component for this URI. + # + # @param [String, #to_str] new_query The new query component. + def query=(new_query) + if new_query && !new_query.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_query.class} into String." + end + @query = new_query ? new_query.to_str : nil + + # Reset dependant values + @normalized_query = nil + @uri_string = nil + @hash = nil + end + + ## + # Converts the query component to a Hash value. + # + # @param [Class] return_type The return type desired. Value must be either + # `Hash` or `Array`. + # + # @return [Hash, Array] The query string parsed as a Hash or Array object. + # + # @example + # Addressable::URI.parse("?one=1&two=2&three=3").query_values + # #=> {"one" => "1", "two" => "2", "three" => "3"} + # Addressable::URI.parse("?one=two&one=three").query_values(Array) + # #=> [["one", "two"], ["one", "three"]] + # Addressable::URI.parse("?one=two&one=three").query_values(Hash) + # #=> {"one" => "three"} + def query_values(return_type=Hash) + empty_accumulator = Array == return_type ? [] : {} + if return_type != Hash && return_type != Array + raise ArgumentError, "Invalid return type. Must be Hash or Array." + end + return nil if self.query == nil + split_query = (self.query.split("&").map do |pair| + pair.split("=", 2) if pair && !pair.empty? + end).compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + # I'd rather use key/value identifiers instead of array lookups, + # but in this case I really want to maintain the exact pair structure, + # so it's best to make all changes in-place. + pair[0] = URI.unencode_component(pair[0]) + if pair[1].respond_to?(:to_str) + # I loathe the fact that I have to do this. Stupid HTML 4.01. + # Treating '+' as a space was just an unbelievably bad idea. + # There was nothing wrong with '%20'! + # If it ain't broke, don't fix it! + pair[1] = URI.unencode_component(pair[1].to_str.gsub(/\+/, " ")) + end + if return_type == Hash + accu[pair[0]] = pair[1] + else + accu << pair + end + accu + end + end + + ## + # Sets the query component for this URI from a Hash object. + # An empty Hash or Array will result in an empty query string. + # + # @param [Hash, #to_hash, Array] new_query_values The new query values. + # + # @example + # uri.query_values = {:a => "a", :b => ["c", "d", "e"]} + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['flag'], ['key', 'value']] + # uri.query + # # => "flag&key=value" + def query_values=(new_query_values) + if new_query_values == nil + self.query = nil + return nil + end + + if !new_query_values.is_a?(Array) + if !new_query_values.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{new_query_values.class} into Hash." + end + new_query_values = new_query_values.to_hash + new_query_values = new_query_values.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + new_query_values.sort! + end + + # new_query_values have form [['key1', 'value1'], ['key2', 'value2']] + buffer = "" + new_query_values.each do |key, value| + encoded_key = URI.encode_component( + key, CharacterClasses::UNRESERVED + ) + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = URI.encode_component( + sub_value, CharacterClasses::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = URI.encode_component( + value, CharacterClasses::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + self.query = buffer.chop + end + + ## + # The HTTP request URI for this URI. This is the path and the + # query string. + # + # @return [String] The request URI required for an HTTP request. + def request_uri + return nil if self.absolute? && self.scheme !~ /^https?$/ + return ( + (!self.path.empty? ? self.path : SLASH) + + (self.query ? "?#{self.query}" : EMPTY_STR) + ) + end + + ## + # Sets the HTTP request URI for this URI. + # + # @param [String, #to_str] new_request_uri The new HTTP request URI. + def request_uri=(new_request_uri) + if !new_request_uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_request_uri.class} into String." + end + if self.absolute? && self.scheme !~ /^https?$/ + raise InvalidURIError, + "Cannot set an HTTP request URI for a non-HTTP URI." + end + new_request_uri = new_request_uri.to_str + path_component = new_request_uri[/^([^\?]*)\?(?:.*)$/, 1] + query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1] + path_component = path_component.to_s + path_component = (!path_component.empty? ? path_component : SLASH) + self.path = path_component + self.query = query_component + + # Reset dependant values + @uri_string = nil + @hash = nil + end + + ## + # The fragment component for this URI. + # + # @return [String] The fragment component. + def fragment + return instance_variable_defined?(:@fragment) ? @fragment : nil + end + + ## + # The fragment component for this URI, normalized. + # + # @return [String] The fragment component, normalized. + def normalized_fragment + self.fragment && @normalized_fragment ||= (begin + component = Addressable::URI.normalize_component( + self.fragment, + Addressable::URI::CharacterClasses::FRAGMENT + ) + component == "" ? nil : component + end) + end + + ## + # Sets the fragment component for this URI. + # + # @param [String, #to_str] new_fragment The new fragment component. + def fragment=(new_fragment) + if new_fragment && !new_fragment.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_fragment.class} into String." + end + @fragment = new_fragment ? new_fragment.to_str : nil + + # Reset dependant values + @normalized_fragment = nil + @uri_string = nil + @hash = nil + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # Determines if the scheme indicates an IP-based protocol. + # + # @return [TrueClass, FalseClass] + # true if the scheme indicates an IP-based protocol. + # false otherwise. + def ip_based? + if self.scheme + return URI.ip_based_schemes.include?( + self.scheme.strip.downcase) + end + return false + end + + ## + # Determines if the URI is relative. + # + # @return [TrueClass, FalseClass] + # true if the URI is relative. false + # otherwise. + def relative? + return self.scheme.nil? + end + + ## + # Determines if the URI is absolute. + # + # @return [TrueClass, FalseClass] + # true if the URI is absolute. false + # otherwise. + def absolute? + return !relative? + end + + ## + # Joins two URIs together. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + def join(uri) + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + if !uri.kind_of?(URI) + # Otherwise, convert to a String, then parse. + uri = URI.parse(uri.to_str) + end + if uri.to_s.empty? + return self.dup + end + + joined_scheme = nil + joined_user = nil + joined_password = nil + joined_host = nil + joined_port = nil + joined_path = nil + joined_query = nil + joined_fragment = nil + + # Section 5.2.2 of RFC 3986 + if uri.scheme != nil + joined_scheme = uri.scheme + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.authority != nil + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.path == nil || uri.path.empty? + joined_path = self.path + if uri.query != nil + joined_query = uri.query + else + joined_query = self.query + end + else + if uri.path[0..0] == SLASH + joined_path = URI.normalize_path(uri.path) + else + base_path = self.path.dup + base_path = EMPTY_STR if base_path == nil + base_path = URI.normalize_path(base_path) + + # Section 5.2.3 of RFC 3986 + # + # Removes the right-most path segment from the base path. + if base_path =~ /\// + base_path.gsub!(/\/[^\/]+$/, SLASH) + else + base_path = EMPTY_STR + end + + # If the base path is empty and an authority segment has been + # defined, use a base path of SLASH + if base_path.empty? && self.authority != nil + base_path = SLASH + end + + joined_path = URI.normalize_path(base_path + uri.path) + end + joined_query = uri.query + end + joined_user = self.user + joined_password = self.password + joined_host = self.host + joined_port = self.port + end + joined_scheme = self.scheme + end + joined_fragment = uri.fragment + + return self.class.new( + :scheme => joined_scheme, + :user => joined_user, + :password => joined_password, + :host => joined_host, + :port => joined_port, + :path => joined_path, + :query => joined_query, + :fragment => joined_fragment + ) + end + alias_method :+, :join + + ## + # Destructive form of join. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + # + # @see Addressable::URI#join + def join!(uri) + replace_self(self.join(uri)) + end + + ## + # Merges a URI with a Hash of components. + # This method has different behavior from join. Any + # components present in the hash parameter will override the + # original components. The path component is not treated specially. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Hash#merge + def merge(hash) + if !hash.respond_to?(:to_hash) + raise TypeError, "Can't convert #{hash.class} into Hash." + end + hash = hash.to_hash + + if hash.has_key?(:authority) + if (hash.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if hash.has_key?(:userinfo) + if (hash.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + uri = self.class.new + uri.defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + uri.scheme = + hash.has_key?(:scheme) ? hash[:scheme] : self.scheme + if hash.has_key?(:authority) + uri.authority = + hash.has_key?(:authority) ? hash[:authority] : self.authority + end + if hash.has_key?(:userinfo) + uri.userinfo = + hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo + end + if !hash.has_key?(:userinfo) && !hash.has_key?(:authority) + uri.user = + hash.has_key?(:user) ? hash[:user] : self.user + uri.password = + hash.has_key?(:password) ? hash[:password] : self.password + end + if !hash.has_key?(:authority) + uri.host = + hash.has_key?(:host) ? hash[:host] : self.host + uri.port = + hash.has_key?(:port) ? hash[:port] : self.port + end + uri.path = + hash.has_key?(:path) ? hash[:path] : self.path + uri.query = + hash.has_key?(:query) ? hash[:query] : self.query + uri.fragment = + hash.has_key?(:fragment) ? hash[:fragment] : self.fragment + end + + return uri + end + + ## + # Destructive form of merge. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Addressable::URI#merge + def merge!(uri) + replace_self(self.merge(uri)) + end + + ## + # Returns the shortest normalized relative form of this URI that uses the + # supplied URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_to. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route from. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the original URI. + def route_from(uri) + uri = URI.parse(uri).normalize + normalized_self = self.normalize + if normalized_self.relative? + raise ArgumentError, "Expected absolute URI, got: #{self.to_s}" + end + if uri.relative? + raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}" + end + if normalized_self == uri + return Addressable::URI.parse("##{normalized_self.fragment}") + end + components = normalized_self.to_hash + if normalized_self.scheme == uri.scheme + components[:scheme] = nil + if normalized_self.authority == uri.authority + components[:user] = nil + components[:password] = nil + components[:host] = nil + components[:port] = nil + if normalized_self.path == uri.path + components[:path] = nil + if normalized_self.query == uri.query + components[:query] = nil + end + else + if uri.path != SLASH and components[:path] + self_splitted_path = split_path(components[:path]) + uri_splitted_path = split_path(uri.path) + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + while !self_splitted_path.empty? && !uri_splitted_path.empty? and self_dir == uri_dir + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + end + components[:path] = (uri_splitted_path.fill('..') + [self_dir] + self_splitted_path).join(SLASH) + end + end + end + end + # Avoid network-path references. + if components[:host] != nil + components[:scheme] = normalized_self.scheme + end + return Addressable::URI.new( + :scheme => components[:scheme], + :user => components[:user], + :password => components[:password], + :host => components[:host], + :port => components[:port], + :path => components[:path], + :query => components[:query], + :fragment => components[:fragment] + ) + end + + ## + # Returns the shortest normalized relative form of the supplied URI that + # uses this URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_from. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route to. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the supplied URI. + def route_to(uri) + return URI.parse(uri).route_from(self) + end + + ## + # Returns a normalized URI object. + # + # NOTE: This method does not attempt to fully conform to specifications. + # It exists largely to correct other people's failures to read the + # specifications, and also to deal with caching issues since several + # different URIs may represent the same resource and should not be + # cached multiple times. + # + # @return [Addressable::URI] The normalized URI. + def normalize + # This is a special exception for the frequently misused feed + # URI scheme. + if normalized_scheme == "feed" + if self.to_s =~ /^feed:\/*http:\/*/ + return URI.parse( + self.to_s[/^feed:\/*(http:\/*.*)/, 1] + ).normalize + end + end + + return self.class.new( + :scheme => normalized_scheme, + :authority => normalized_authority, + :path => normalized_path, + :query => normalized_query, + :fragment => normalized_fragment + ) + end + + ## + # Destructively normalizes this URI object. + # + # @return [Addressable::URI] The normalized URI. + # + # @see Addressable::URI#normalize + def normalize! + replace_self(self.normalize) + end + + ## + # Creates a URI suitable for display to users. If semantic attacks are + # likely, the application should try to detect these and warn the user. + # See RFC 3986, + # section 7.6 for more information. + # + # @return [Addressable::URI] A URI suitable for display purposes. + def display_uri + display_uri = self.normalize + display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host) + return display_uri + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison, and allows comparison + # against Strings. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ===(uri) + if uri.respond_to?(:normalize) + uri_string = uri.normalize.to_s + else + begin + uri_string = ::Addressable::URI.parse(uri).normalize.to_s + rescue InvalidURIError, TypeError + return false + end + end + return self.normalize.to_s == uri_string + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ==(uri) + return false unless uri.kind_of?(URI) + return self.normalize.to_s == uri.normalize.to_s + end + + ## + # Returns true if the URI objects are equal. This method + # does NOT normalize either URI before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def eql?(uri) + return false unless uri.kind_of?(URI) + return self.to_s == uri.to_s + end + + ## + # A hash value that will make a URI equivalent to its normalized + # form. + # + # @return [Integer] A hash of the URI. + def hash + return @hash ||= (self.to_s.hash * -1) + end + + ## + # Clones the URI object. + # + # @return [Addressable::URI] The cloned URI. + def dup + duplicated_uri = self.class.new( + :scheme => self.scheme ? self.scheme.dup : nil, + :user => self.user ? self.user.dup : nil, + :password => self.password ? self.password.dup : nil, + :host => self.host ? self.host.dup : nil, + :port => self.port, + :path => self.path ? self.path.dup : nil, + :query => self.query ? self.query.dup : nil, + :fragment => self.fragment ? self.fragment.dup : nil + ) + return duplicated_uri + end + + ## + # Omits components from a URI. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @example + # uri = Addressable::URI.parse("http://example.com/path?query") + # #=> # + # uri.omit(:scheme, :authority) + # #=> # + def omit(*components) + invalid_components = components - [ + :scheme, :user, :password, :userinfo, :host, :port, :authority, + :path, :query, :fragment + ] + unless invalid_components.empty? + raise ArgumentError, + "Invalid component names: #{invalid_components.inspect}." + end + duplicated_uri = self.dup + duplicated_uri.defer_validation do + components.each do |component| + duplicated_uri.send((component.to_s + "=").to_sym, nil) + end + duplicated_uri.user = duplicated_uri.normalized_user + end + duplicated_uri + end + + ## + # Destructive form of omit. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @see Addressable::URI#omit + def omit!(*components) + replace_self(self.omit(*components)) + end + + ## + # Determines if the URI is an empty string. + # + # @return [TrueClass, FalseClass] + # Returns true if empty, false otherwise. + def empty? + return self.to_s.empty? + end + + ## + # Converts the URI to a String. + # + # @return [String] The URI's String representation. + def to_s + if self.scheme == nil && self.path != nil && !self.path.empty? && + self.path =~ NORMPATH + raise InvalidURIError, + "Cannot assemble URI string with ambiguous path: '#{self.path}'" + end + @uri_string ||= (begin + uri_string = "" + uri_string << "#{self.scheme}:" if self.scheme != nil + uri_string << "//#{self.authority}" if self.authority != nil + uri_string << self.path.to_s + uri_string << "?#{self.query}" if self.query != nil + uri_string << "##{self.fragment}" if self.fragment != nil + if uri_string.respond_to?(:force_encoding) + uri_string.force_encoding(Encoding::UTF_8) + end + uri_string + end) + end + + ## + # URI's are glorified Strings. Allow implicit conversion. + alias_method :to_str, :to_s + + ## + # Returns a Hash of the URI components. + # + # @return [Hash] The URI as a Hash of components. + def to_hash + return { + :scheme => self.scheme, + :user => self.user, + :password => self.password, + :host => self.host, + :port => self.port, + :path => self.path, + :query => self.query, + :fragment => self.fragment + } + end + + ## + # Returns a String representation of the URI object's state. + # + # @return [String] The URI object's state, as a String. + def inspect + sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s) + end + + ## + # This method allows you to make several changes to a URI simultaneously, + # which separately would cause validation errors, but in conjunction, + # are valid. The URI will be revalidated as soon as the entire block has + # been executed. + # + # @param [Proc] block + # A set of operations to perform on a given URI. + def defer_validation(&block) + raise LocalJumpError, "No block given." unless block + @validation_deferred = true + block.call() + @validation_deferred = false + validate + return nil + end + + private + SELF_REF = '.' + PARENT = '..' + + RULE_2A = /\/\.\/|\/\.$/ + RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/ + RULE_2D = /^\.\.?\/?/ + RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/ + + ## + # Resolves paths to their simplest form. + # + # @param [String] path The path to normalize. + # + # @return [String] The normalized path. + def self.normalize_path(path) + # Section 5.2.4 of RFC 3986 + + return nil if path.nil? + normalized_path = path.dup + begin + mod = nil + mod ||= normalized_path.gsub!(RULE_2A, SLASH) + + pair = normalized_path.match(RULE_2B_2C) + parent, current = pair[1], pair[2] if pair + if pair && ((parent != SELF_REF && parent != PARENT) || + (current != SELF_REF && current != PARENT)) + mod ||= normalized_path.gsub!( + Regexp.new( + "/#{Regexp.escape(parent.to_s)}/\\.\\./|" + + "(/#{Regexp.escape(current.to_s)}/\\.\\.$)" + ), SLASH + ) + end + + mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR) + # Non-standard, removes prefixed dotted segments from path. + mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH) + end until mod.nil? + + return normalized_path + end + + ## + # Ensures that the URI is valid. + def validate + return if !!@validation_deferred + if self.scheme != nil && self.ip_based? && + (self.host == nil || self.host.empty?) && + (self.path == nil || self.path.empty?) + raise InvalidURIError, + "Absolute URI missing hierarchical segment: '#{self.to_s}'" + end + if self.host == nil + if self.port != nil || + self.user != nil || + self.password != nil + raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'" + end + end + if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH && + self.authority != nil + raise InvalidURIError, + "Cannot have a relative path with an authority set: '#{self.to_s}'" + end + return nil + end + + ## + # Replaces the internal state of self with the specified URI's state. + # Used in destructive operations to avoid massive code repetition. + # + # @param [Addressable::URI] uri The URI to replace self with. + # + # @return [Addressable::URI] self. + def replace_self(uri) + # Reset dependant values + instance_variables.each do |var| + instance_variable_set(var, nil) + end + + @scheme = uri.scheme + @user = uri.user + @password = uri.password + @host = uri.host + @port = uri.port + @path = uri.path + @query = uri.query + @fragment = uri.fragment + return self + end + + ## + # Splits path string with "/"(slash). + # It is considered that there is empty string after last slash when + # path ends with slash. + # + # @param [String] path The path to split. + # + # @return [Array] An array of parts of path. + def split_path(path) + splitted = path.split(SLASH) + splitted << EMPTY_STR if path.end_with? SLASH + splitted + end + end +end diff --git a/.gems/gems/addressable-2.3.6/lib/addressable/version.rb b/.gems/gems/addressable-2.3.6/lib/addressable/version.rb new file mode 100644 index 0000000..75a9ad8 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/lib/addressable/version.rb @@ -0,0 +1,30 @@ +# encoding:utf-8 +#-- +# Copyright (C) 2006-2013 Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +# Used to prevent the class/module from being loaded more than once +if !defined?(Addressable::VERSION) + module Addressable + module VERSION + MAJOR = 2 + MINOR = 3 + TINY = 6 + + STRING = [MAJOR, MINOR, TINY].join('.') + end + end +end diff --git a/.gems/gems/addressable-2.3.6/spec/addressable/idna_spec.rb b/.gems/gems/addressable-2.3.6/spec/addressable/idna_spec.rb new file mode 100644 index 0000000..b3c778a --- /dev/null +++ b/.gems/gems/addressable-2.3.6/spec/addressable/idna_spec.rb @@ -0,0 +1,238 @@ +# coding: utf-8 +# Copyright (C) 2006-2013 Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +# Have to use RubyGems to load the idn gem. +require "rubygems" + +require "addressable/idna" + +shared_examples_for "converting from unicode to ASCII" do + it "should convert 'www.google.com' correctly" do + Addressable::IDNA.to_ascii("www.google.com").should == "www.google.com" + end + + it "should convert 'www.詹姆斯.com' correctly" do + Addressable::IDNA.to_ascii( + "www.詹姆斯.com" + ).should == "www.xn--8ws00zhy3a.com" + end + + it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do + "www.Iñtërnâtiônàlizætiøn.com" + Addressable::IDNA.to_ascii( + "www.I\xC3\xB1t\xC3\xABrn\xC3\xA2ti\xC3\xB4" + + "n\xC3\xA0liz\xC3\xA6ti\xC3\xB8n.com" + ).should == "www.xn--itrntinliztin-vdb0a5exd8ewcye.com" + end + + it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do + Addressable::IDNA.to_ascii( + "www.In\xCC\x83te\xCC\x88rna\xCC\x82tio\xCC\x82n" + + "a\xCC\x80liz\xC3\xA6ti\xC3\xB8n.com" + ).should == "www.xn--itrntinliztin-vdb0a5exd8ewcye.com" + end + + it "should convert " + + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + + "correctly" do + Addressable::IDNA.to_ascii( + "www.\343\201\273\343\202\223\343\201\250\343\201\206\343\201\253\343" + + "\201\252\343\201\214\343\201\204\343\202\217\343\201\221\343\201\256" + + "\343\202\217\343\201\213\343\202\211\343\201\252\343\201\204\343\201" + + "\251\343\202\201\343\201\204\343\202\223\343\202\201\343\201\204\343" + + "\201\256\343\202\211\343\201\271\343\202\213\343\201\276\343\201\240" + + "\343\201\252\343\201\214\343\201\217\343\201\227\343\201\252\343\201" + + "\204\343\201\250\343\201\237\343\202\212\343\201\252\343\201\204." + + "w3.mag.keio.ac.jp" + ).should == + "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + end + + it "should convert " + + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + + "correctly" do + Addressable::IDNA.to_ascii( + "www.\343\201\273\343\202\223\343\201\250\343\201\206\343\201\253\343" + + "\201\252\343\201\213\343\202\231\343\201\204\343\202\217\343\201\221" + + "\343\201\256\343\202\217\343\201\213\343\202\211\343\201\252\343\201" + + "\204\343\201\250\343\202\231\343\202\201\343\201\204\343\202\223\343" + + "\202\201\343\201\204\343\201\256\343\202\211\343\201\270\343\202\231" + + "\343\202\213\343\201\276\343\201\237\343\202\231\343\201\252\343\201" + + "\213\343\202\231\343\201\217\343\201\227\343\201\252\343\201\204\343" + + "\201\250\343\201\237\343\202\212\343\201\252\343\201\204." + + "w3.mag.keio.ac.jp" + ).should == + "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + end + + it "should convert '点心和烤鸭.w3.mag.keio.ac.jp' correctly" do + Addressable::IDNA.to_ascii( + "点心和烤鸭.w3.mag.keio.ac.jp" + ).should == "xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp" + end + + it "should convert '가각갂갃간갅갆갇갈갉힢힣.com' correctly" do + Addressable::IDNA.to_ascii( + "가각갂갃간갅갆갇갈갉힢힣.com" + ).should == "xn--o39acdefghijk5883jma.com" + end + + it "should convert " + + "'\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com' correctly" do + Addressable::IDNA.to_ascii( + "\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com" + ).should == "xn--9cs565brid46mda086o.com" + end + + it "should convert 'リ宠퐱〹.com' correctly" do + Addressable::IDNA.to_ascii( + "\357\276\230\345\256\240\355\220\261\343\200\271.com" + ).should == "xn--eek174hoxfpr4k.com" + end + + it "should convert 'リ宠퐱卄.com' correctly" do + Addressable::IDNA.to_ascii( + "\343\203\252\345\256\240\355\220\261\345\215\204.com" + ).should == "xn--eek174hoxfpr4k.com" + end + + it "should convert 'ᆵ' correctly" do + Addressable::IDNA.to_ascii( + "\341\206\265" + ).should == "xn--4ud" + end + + it "should convert 'ᆵ' correctly" do + Addressable::IDNA.to_ascii( + "\357\276\257" + ).should == "xn--4ud" + end +end + +shared_examples_for "converting from ASCII to unicode" do + it "should convert 'www.google.com' correctly" do + Addressable::IDNA.to_unicode("www.google.com").should == "www.google.com" + end + + it "should convert 'www.詹姆斯.com' correctly" do + Addressable::IDNA.to_unicode( + "www.xn--8ws00zhy3a.com" + ).should == "www.詹姆斯.com" + end + + it "should convert 'www.iñtërnâtiônàlizætiøn.com' correctly" do + Addressable::IDNA.to_unicode( + "www.xn--itrntinliztin-vdb0a5exd8ewcye.com" + ).should == "www.iñtërnâtiônàlizætiøn.com" + end + + it "should convert " + + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + + "correctly" do + Addressable::IDNA.to_unicode( + "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + ).should == + "www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp" + end + + it "should convert '点心和烤鸭.w3.mag.keio.ac.jp' correctly" do + Addressable::IDNA.to_unicode( + "xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp" + ).should == "点心和烤鸭.w3.mag.keio.ac.jp" + end + + it "should convert '가각갂갃간갅갆갇갈갉힢힣.com' correctly" do + Addressable::IDNA.to_unicode( + "xn--o39acdefghijk5883jma.com" + ).should == "가각갂갃간갅갆갇갈갉힢힣.com" + end + + it "should convert " + + "'\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com' correctly" do + Addressable::IDNA.to_unicode( + "xn--9cs565brid46mda086o.com" + ).should == + "\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com" + end + + it "should convert 'リ宠퐱卄.com' correctly" do + Addressable::IDNA.to_unicode( + "xn--eek174hoxfpr4k.com" + ).should == "\343\203\252\345\256\240\355\220\261\345\215\204.com" + end + + it "should convert 'ᆵ' correctly" do + Addressable::IDNA.to_unicode( + "xn--4ud" + ).should == "\341\206\265" + end + + it "should normalize 'string' correctly" do + Addressable::IDNA.unicode_normalize_kc(:'string').should == "string" + Addressable::IDNA.unicode_normalize_kc("string").should == "string" + end +end + +describe Addressable::IDNA, "when using the pure-Ruby implementation" do + before do + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/pure.rb" + end + + it_should_behave_like "converting from unicode to ASCII" + it_should_behave_like "converting from ASCII to unicode" + + begin + require "fiber" + + it "should not blow up inside fibers" do + f = Fiber.new do + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/pure.rb" + end + f.resume + end + rescue LoadError + # Fibers aren't supported in this version of Ruby, skip this test. + warn('Fibers unsupported.') + end +end + +begin + require "idn" + + describe Addressable::IDNA, "when using the native-code implementation" do + before do + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/native.rb" + end + + it_should_behave_like "converting from unicode to ASCII" + it_should_behave_like "converting from ASCII to unicode" + end +rescue LoadError + # Cannot test the native implementation without libidn support. + warn('Could not load native IDN implementation.') +end diff --git a/.gems/gems/addressable-2.3.6/spec/addressable/net_http_compat_spec.rb b/.gems/gems/addressable-2.3.6/spec/addressable/net_http_compat_spec.rb new file mode 100644 index 0000000..87a3bdd --- /dev/null +++ b/.gems/gems/addressable-2.3.6/spec/addressable/net_http_compat_spec.rb @@ -0,0 +1,28 @@ +# coding: utf-8 +# Copyright (C) 2006-2013 Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "addressable/uri" +require "net/http" + +describe Net::HTTP do + it "should be compatible with Addressable" do + response_body = + Net::HTTP.get(Addressable::URI.parse('http://www.google.com/')) + response_body.should_not be_nil + end +end diff --git a/.gems/gems/addressable-2.3.6/spec/addressable/template_spec.rb b/.gems/gems/addressable-2.3.6/spec/addressable/template_spec.rb new file mode 100644 index 0000000..759c19d --- /dev/null +++ b/.gems/gems/addressable-2.3.6/spec/addressable/template_spec.rb @@ -0,0 +1,1328 @@ +# coding: utf-8 +# Copyright (C) 2006-2013 Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "addressable/template" + +shared_examples_for 'expands' do |tests| + tests.each do |template, expansion| + exp = expansion.is_a?(Array) ? expansion.first : expansion + it "#{template} to #{exp}" do + tmpl = Addressable::Template.new(template).expand(subject) + if expansion.is_a?(Array) + expansion.any?{|i| i == tmpl.to_str}.should be_true + else + tmpl.to_str.should == expansion + end + end + end +end + +describe "eql?" do + let(:template) { Addressable::Template.new('https://www.example.com/{foo}') } + it 'is equal when the pattern matches' do + other_template = Addressable::Template.new('https://www.example.com/{foo}') + expect(template).to be_eql(other_template) + expect(other_template).to be_eql(template) + end + it 'is not equal when the pattern differs' do + other_template = Addressable::Template.new('https://www.example.com/{bar}') + expect(template).to_not be_eql(other_template) + expect(other_template).to_not be_eql(template) + end + it 'is not equal to non-templates' do + uri = 'https://www.example.com/foo/bar' + addressable_template = Addressable::Template.new uri + addressable_uri = Addressable::URI.parse uri + expect(addressable_template).to_not be_eql(addressable_uri) + expect(addressable_uri).to_not be_eql(addressable_template) + end +end + +describe "==" do + let(:template) { Addressable::Template.new('https://www.example.com/{foo}') } + it 'is equal when the pattern matches' do + other_template = Addressable::Template.new('https://www.example.com/{foo}') + expect(template).should == other_template + expect(other_template).should == template + end + it 'is not equal when the pattern differs' do + other_template = Addressable::Template.new('https://www.example.com/{bar}') + expect(template).should_not == other_template + expect(other_template).should_not == template + end + it 'is not equal to non-templates' do + uri = 'https://www.example.com/foo/bar' + addressable_template = Addressable::Template.new uri + addressable_uri = Addressable::URI.parse uri + expect(addressable_template).should_not == addressable_uri + expect(addressable_uri).should_not == addressable_template + end +end + +describe "Type conversion" do + require "bigdecimal" + + subject { + { + :var => true, + :hello => 1234, + :nothing => nil, + :sym => :symbolic, + :decimal => BigDecimal.new(1) + } + } + + it_behaves_like 'expands', { + '{var}' => 'true', + '{hello}' => '1234', + '{nothing}' => '', + '{sym}' => 'symbolic', + '{decimal}' => '0.1E1' + } +end + +describe "Level 1:" do + subject { + {:var => "value", :hello => "Hello World!"} + } + it_behaves_like 'expands', { + '{var}' => 'value', + '{hello}' => 'Hello%20World%21' + } +end + +describe "Level 2" do + subject { + { + :var => "value", + :hello => "Hello World!", + :path => "/foo/bar" + } + } + context "Operator +:" do + it_behaves_like 'expands', { + '{+var}' => 'value', + '{+hello}' => 'Hello%20World!', + '{+path}/here' => '/foo/bar/here', + 'here?ref={+path}' => 'here?ref=/foo/bar' + } + end + context "Operator #:" do + it_behaves_like 'expands', { + 'X{#var}' => 'X#value', + 'X{#hello}' => 'X#Hello%20World!' + } + end +end + +describe "Level 3" do + subject { + { + :var => "value", + :hello => "Hello World!", + :empty => "", + :path => "/foo/bar", + :x => "1024", + :y => "768" + } + } + context "Operator nil (multiple vars):" do + it_behaves_like 'expands', { + 'map?{x,y}' => 'map?1024,768', + '{x,hello,y}' => '1024,Hello%20World%21,768' + } + end + context "Operator + (multiple vars):" do + it_behaves_like 'expands', { + '{+x,hello,y}' => '1024,Hello%20World!,768', + '{+path,x}/here' => '/foo/bar,1024/here' + } + end + context "Operator # (multiple vars):" do + it_behaves_like 'expands', { + '{#x,hello,y}' => '#1024,Hello%20World!,768', + '{#path,x}/here' => '#/foo/bar,1024/here' + } + end + context "Operator ." do + it_behaves_like 'expands', { + 'X{.var}' => 'X.value', + 'X{.x,y}' => 'X.1024.768' + } + end + context "Operator /" do + it_behaves_like 'expands', { + '{/var}' => '/value', + '{/var,x}/here' => '/value/1024/here' + } + end + context "Operator ;" do + it_behaves_like 'expands', { + '{;x,y}' => ';x=1024;y=768', + '{;x,y,empty}' => ';x=1024;y=768;empty' + } + end + context "Operator ?" do + it_behaves_like 'expands', { + '{?x,y}' => '?x=1024&y=768', + '{?x,y,empty}' => '?x=1024&y=768&empty=' + } + end + context "Operator &" do + it_behaves_like 'expands', { + '?fixed=yes{&x}' => '?fixed=yes&x=1024', + '{&x,y,empty}' => '&x=1024&y=768&empty=' + } + end +end + +describe "Level 4" do + subject { + { + :var => "value", + :hello => "Hello World!", + :path => "/foo/bar", + :semi => ";", + :list => %w(red green blue), + :keys => {"semi" => ';', "dot" => '.', "comma" => ','} + } + } + context "Expansion with value modifiers" do + it_behaves_like 'expands', { + '{var:3}' => 'val', + '{var:30}' => 'value', + '{list}' => 'red,green,blue', + '{list*}' => 'red,green,blue', + '{keys}' => [ + 'semi,%3B,dot,.,comma,%2C', + 'dot,.,semi,%3B,comma,%2C', + 'comma,%2C,semi,%3B,dot,.', + 'semi,%3B,comma,%2C,dot,.', + 'dot,.,comma,%2C,semi,%3B', + 'comma,%2C,dot,.,semi,%3B' + ], + '{keys*}' => [ + 'semi=%3B,dot=.,comma=%2C', + 'dot=.,semi=%3B,comma=%2C', + 'comma=%2C,semi=%3B,dot=.', + 'semi=%3B,comma=%2C,dot=.', + 'dot=.,comma=%2C,semi=%3B', + 'comma=%2C,dot=.,semi=%3B' + ] + } + end + context "Operator + with value modifiers" do + it_behaves_like 'expands', { + '{+path:6}/here' => '/foo/b/here', + '{+list}' => 'red,green,blue', + '{+list*}' => 'red,green,blue', + '{+keys}' => [ + 'semi,;,dot,.,comma,,', + 'dot,.,semi,;,comma,,', + 'comma,,,semi,;,dot,.', + 'semi,;,comma,,,dot,.', + 'dot,.,comma,,,semi,;', + 'comma,,,dot,.,semi,;' + ], + '{+keys*}' => [ + 'semi=;,dot=.,comma=,', + 'dot=.,semi=;,comma=,', + 'comma=,,semi=;,dot=.', + 'semi=;,comma=,,dot=.', + 'dot=.,comma=,,semi=;', + 'comma=,,dot=.,semi=;' + ] + } + end + context "Operator # with value modifiers" do + it_behaves_like 'expands', { + '{#path:6}/here' => '#/foo/b/here', + '{#list}' => '#red,green,blue', + '{#list*}' => '#red,green,blue', + '{#keys}' => [ + '#semi,;,dot,.,comma,,', + '#dot,.,semi,;,comma,,', + '#comma,,,semi,;,dot,.', + '#semi,;,comma,,,dot,.', + '#dot,.,comma,,,semi,;', + '#comma,,,dot,.,semi,;' + ], + '{#keys*}' => [ + '#semi=;,dot=.,comma=,', + '#dot=.,semi=;,comma=,', + '#comma=,,semi=;,dot=.', + '#semi=;,comma=,,dot=.', + '#dot=.,comma=,,semi=;', + '#comma=,,dot=.,semi=;' + ] + } + end + context "Operator . with value modifiers" do + it_behaves_like 'expands', { + 'X{.var:3}' => 'X.val', + 'X{.list}' => 'X.red,green,blue', + 'X{.list*}' => 'X.red.green.blue', + 'X{.keys}' => [ + 'X.semi,%3B,dot,.,comma,%2C', + 'X.dot,.,semi,%3B,comma,%2C', + 'X.comma,%2C,semi,%3B,dot,.', + 'X.semi,%3B,comma,%2C,dot,.', + 'X.dot,.,comma,%2C,semi,%3B', + 'X.comma,%2C,dot,.,semi,%3B' + ], + 'X{.keys*}' => [ + 'X.semi=%3B.dot=..comma=%2C', + 'X.dot=..semi=%3B.comma=%2C', + 'X.comma=%2C.semi=%3B.dot=.', + 'X.semi=%3B.comma=%2C.dot=.', + 'X.dot=..comma=%2C.semi=%3B', + 'X.comma=%2C.dot=..semi=%3B' + ] + } + end + context "Operator / with value modifiers" do + it_behaves_like 'expands', { + '{/var:1,var}' => '/v/value', + '{/list}' => '/red,green,blue', + '{/list*}' => '/red/green/blue', + '{/list*,path:4}' => '/red/green/blue/%2Ffoo', + '{/keys}' => [ + '/semi,%3B,dot,.,comma,%2C', + '/dot,.,semi,%3B,comma,%2C', + '/comma,%2C,semi,%3B,dot,.', + '/semi,%3B,comma,%2C,dot,.', + '/dot,.,comma,%2C,semi,%3B', + '/comma,%2C,dot,.,semi,%3B' + ], + '{/keys*}' => [ + '/semi=%3B/dot=./comma=%2C', + '/dot=./semi=%3B/comma=%2C', + '/comma=%2C/semi=%3B/dot=.', + '/semi=%3B/comma=%2C/dot=.', + '/dot=./comma=%2C/semi=%3B', + '/comma=%2C/dot=./semi=%3B' + ] + } + end + context "Operator ; with value modifiers" do + it_behaves_like 'expands', { + '{;hello:5}' => ';hello=Hello', + '{;list}' => ';list=red,green,blue', + '{;list*}' => ';list=red;list=green;list=blue', + '{;keys}' => [ + ';keys=semi,%3B,dot,.,comma,%2C', + ';keys=dot,.,semi,%3B,comma,%2C', + ';keys=comma,%2C,semi,%3B,dot,.', + ';keys=semi,%3B,comma,%2C,dot,.', + ';keys=dot,.,comma,%2C,semi,%3B', + ';keys=comma,%2C,dot,.,semi,%3B' + ], + '{;keys*}' => [ + ';semi=%3B;dot=.;comma=%2C', + ';dot=.;semi=%3B;comma=%2C', + ';comma=%2C;semi=%3B;dot=.', + ';semi=%3B;comma=%2C;dot=.', + ';dot=.;comma=%2C;semi=%3B', + ';comma=%2C;dot=.;semi=%3B' + ] + } + end + context "Operator ? with value modifiers" do + it_behaves_like 'expands', { + '{?var:3}' => '?var=val', + '{?list}' => '?list=red,green,blue', + '{?list*}' => '?list=red&list=green&list=blue', + '{?keys}' => [ + '?keys=semi,%3B,dot,.,comma,%2C', + '?keys=dot,.,semi,%3B,comma,%2C', + '?keys=comma,%2C,semi,%3B,dot,.', + '?keys=semi,%3B,comma,%2C,dot,.', + '?keys=dot,.,comma,%2C,semi,%3B', + '?keys=comma,%2C,dot,.,semi,%3B' + ], + '{?keys*}' => [ + '?semi=%3B&dot=.&comma=%2C', + '?dot=.&semi=%3B&comma=%2C', + '?comma=%2C&semi=%3B&dot=.', + '?semi=%3B&comma=%2C&dot=.', + '?dot=.&comma=%2C&semi=%3B', + '?comma=%2C&dot=.&semi=%3B' + ] + } + end + context "Operator & with value modifiers" do + it_behaves_like 'expands', { + '{&var:3}' => '&var=val', + '{&list}' => '&list=red,green,blue', + '{&list*}' => '&list=red&list=green&list=blue', + '{&keys}' => [ + '&keys=semi,%3B,dot,.,comma,%2C', + '&keys=dot,.,semi,%3B,comma,%2C', + '&keys=comma,%2C,semi,%3B,dot,.', + '&keys=semi,%3B,comma,%2C,dot,.', + '&keys=dot,.,comma,%2C,semi,%3B', + '&keys=comma,%2C,dot,.,semi,%3B' + ], + '{&keys*}' => [ + '&semi=%3B&dot=.&comma=%2C', + '&dot=.&semi=%3B&comma=%2C', + '&comma=%2C&semi=%3B&dot=.', + '&semi=%3B&comma=%2C&dot=.', + '&dot=.&comma=%2C&semi=%3B', + '&comma=%2C&dot=.&semi=%3B' + ] + } + end +end +describe "Modifiers" do + subject { + { + :var => "value", + :semi => ";", + :year => %w(1965 2000 2012), + :dom => %w(example com) + } + } + context "length" do + it_behaves_like 'expands', { + '{var:3}' => 'val', + '{var:30}' => 'value', + '{var}' => 'value', + '{semi}' => '%3B', + '{semi:2}' => '%3B' + } + end + context "explode" do + it_behaves_like 'expands', { + 'find{?year*}' => 'find?year=1965&year=2000&year=2012', + 'www{.dom*}' => 'www.example.com', + } + end +end +describe "Expansion" do + subject { + { + :count => ["one", "two", "three"], + :dom => ["example", "com"], + :dub => "me/too", + :hello => "Hello World!", + :half => "50%", + :var => "value", + :who => "fred", + :base => "http://example.com/home/", + :path => "/foo/bar", + :list => ["red", "green", "blue"], + :keys => {"semi" => ";","dot" => ".","comma" => ","}, + :v => "6", + :x => "1024", + :y => "768", + :empty => "", + :empty_keys => {}, + :undef => nil + } + } + context "concatenation" do + it_behaves_like 'expands', { + '{count}' => 'one,two,three', + '{count*}' => 'one,two,three', + '{/count}' => '/one,two,three', + '{/count*}' => '/one/two/three', + '{;count}' => ';count=one,two,three', + '{;count*}' => ';count=one;count=two;count=three', + '{?count}' => '?count=one,two,three', + '{?count*}' => '?count=one&count=two&count=three', + '{&count*}' => '&count=one&count=two&count=three' + } + end + context "simple expansion" do + it_behaves_like 'expands', { + '{var}' => 'value', + '{hello}' => 'Hello%20World%21', + '{half}' => '50%25', + 'O{empty}X' => 'OX', + 'O{undef}X' => 'OX', + '{x,y}' => '1024,768', + '{x,hello,y}' => '1024,Hello%20World%21,768', + '?{x,empty}' => '?1024,', + '?{x,undef}' => '?1024', + '?{undef,y}' => '?768', + '{var:3}' => 'val', + '{var:30}' => 'value', + '{list}' => 'red,green,blue', + '{list*}' => 'red,green,blue', + '{keys}' => [ + 'semi,%3B,dot,.,comma,%2C', + 'dot,.,semi,%3B,comma,%2C', + 'comma,%2C,semi,%3B,dot,.', + 'semi,%3B,comma,%2C,dot,.', + 'dot,.,comma,%2C,semi,%3B', + 'comma,%2C,dot,.,semi,%3B' + ], + '{keys*}' => [ + 'semi=%3B,dot=.,comma=%2C', + 'dot=.,semi=%3B,comma=%2C', + 'comma=%2C,semi=%3B,dot=.', + 'semi=%3B,comma=%2C,dot=.', + 'dot=.,comma=%2C,semi=%3B', + 'comma=%2C,dot=.,semi=%3B' + ] + } + end + context "reserved expansion (+)" do + it_behaves_like 'expands', { + '{+var}' => 'value', + '{+hello}' => 'Hello%20World!', + '{+half}' => '50%25', + '{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex', + '{+base}index' => 'http://example.com/home/index', + 'O{+empty}X' => 'OX', + 'O{+undef}X' => 'OX', + '{+path}/here' => '/foo/bar/here', + 'here?ref={+path}' => 'here?ref=/foo/bar', + 'up{+path}{var}/here' => 'up/foo/barvalue/here', + '{+x,hello,y}' => '1024,Hello%20World!,768', + '{+path,x}/here' => '/foo/bar,1024/here', + '{+path:6}/here' => '/foo/b/here', + '{+list}' => 'red,green,blue', + '{+list*}' => 'red,green,blue', + '{+keys}' => [ + 'semi,;,dot,.,comma,,', + 'dot,.,semi,;,comma,,', + 'comma,,,semi,;,dot,.', + 'semi,;,comma,,,dot,.', + 'dot,.,comma,,,semi,;', + 'comma,,,dot,.,semi,;' + ], + '{+keys*}' => [ + 'semi=;,dot=.,comma=,', + 'dot=.,semi=;,comma=,', + 'comma=,,semi=;,dot=.', + 'semi=;,comma=,,dot=.', + 'dot=.,comma=,,semi=;', + 'comma=,,dot=.,semi=;' + ] + } + end + context "fragment expansion (#)" do + it_behaves_like 'expands', { + '{#var}' => '#value', + '{#hello}' => '#Hello%20World!', + '{#half}' => '#50%25', + 'foo{#empty}' => 'foo#', + 'foo{#undef}' => 'foo', + '{#x,hello,y}' => '#1024,Hello%20World!,768', + '{#path,x}/here' => '#/foo/bar,1024/here', + '{#path:6}/here' => '#/foo/b/here', + '{#list}' => '#red,green,blue', + '{#list*}' => '#red,green,blue', + '{#keys}' => [ + '#semi,;,dot,.,comma,,', + '#dot,.,semi,;,comma,,', + '#comma,,,semi,;,dot,.', + '#semi,;,comma,,,dot,.', + '#dot,.,comma,,,semi,;', + '#comma,,,dot,.,semi,;' + ], + '{#keys*}' => [ + '#semi=;,dot=.,comma=,', + '#dot=.,semi=;,comma=,', + '#comma=,,semi=;,dot=.', + '#semi=;,comma=,,dot=.', + '#dot=.,comma=,,semi=;', + '#comma=,,dot=.,semi=;' + ] + } + end + context "label expansion (.)" do + it_behaves_like 'expands', { + '{.who}' => '.fred', + '{.who,who}' => '.fred.fred', + '{.half,who}' => '.50%25.fred', + 'www{.dom*}' => 'www.example.com', + 'X{.var}' => 'X.value', + 'X{.empty}' => 'X.', + 'X{.undef}' => 'X', + 'X{.var:3}' => 'X.val', + 'X{.list}' => 'X.red,green,blue', + 'X{.list*}' => 'X.red.green.blue', + 'X{.keys}' => [ + 'X.semi,%3B,dot,.,comma,%2C', + 'X.dot,.,semi,%3B,comma,%2C', + 'X.comma,%2C,semi,%3B,dot,.', + 'X.semi,%3B,comma,%2C,dot,.', + 'X.dot,.,comma,%2C,semi,%3B', + 'X.comma,%2C,dot,.,semi,%3B' + ], + 'X{.keys*}' => [ + 'X.semi=%3B.dot=..comma=%2C', + 'X.dot=..semi=%3B.comma=%2C', + 'X.comma=%2C.semi=%3B.dot=.', + 'X.semi=%3B.comma=%2C.dot=.', + 'X.dot=..comma=%2C.semi=%3B', + 'X.comma=%2C.dot=..semi=%3B' + ], + 'X{.empty_keys}' => 'X', + 'X{.empty_keys*}' => 'X' + } + end + context "path expansion (/)" do + it_behaves_like 'expands', { + '{/who}' => '/fred', + '{/who,who}' => '/fred/fred', + '{/half,who}' => '/50%25/fred', + '{/who,dub}' => '/fred/me%2Ftoo', + '{/var}' => '/value', + '{/var,empty}' => '/value/', + '{/var,undef}' => '/value', + '{/var,x}/here' => '/value/1024/here', + '{/var:1,var}' => '/v/value', + '{/list}' => '/red,green,blue', + '{/list*}' => '/red/green/blue', + '{/list*,path:4}' => '/red/green/blue/%2Ffoo', + '{/keys}' => [ + '/semi,%3B,dot,.,comma,%2C', + '/dot,.,semi,%3B,comma,%2C', + '/comma,%2C,semi,%3B,dot,.', + '/semi,%3B,comma,%2C,dot,.', + '/dot,.,comma,%2C,semi,%3B', + '/comma,%2C,dot,.,semi,%3B' + ], + '{/keys*}' => [ + '/semi=%3B/dot=./comma=%2C', + '/dot=./semi=%3B/comma=%2C', + '/comma=%2C/semi=%3B/dot=.', + '/semi=%3B/comma=%2C/dot=.', + '/dot=./comma=%2C/semi=%3B', + '/comma=%2C/dot=./semi=%3B' + ] + } + end + context "path-style expansion (;)" do + it_behaves_like 'expands', { + '{;who}' => ';who=fred', + '{;half}' => ';half=50%25', + '{;empty}' => ';empty', + '{;v,empty,who}' => ';v=6;empty;who=fred', + '{;v,bar,who}' => ';v=6;who=fred', + '{;x,y}' => ';x=1024;y=768', + '{;x,y,empty}' => ';x=1024;y=768;empty', + '{;x,y,undef}' => ';x=1024;y=768', + '{;hello:5}' => ';hello=Hello', + '{;list}' => ';list=red,green,blue', + '{;list*}' => ';list=red;list=green;list=blue', + '{;keys}' => [ + ';keys=semi,%3B,dot,.,comma,%2C', + ';keys=dot,.,semi,%3B,comma,%2C', + ';keys=comma,%2C,semi,%3B,dot,.', + ';keys=semi,%3B,comma,%2C,dot,.', + ';keys=dot,.,comma,%2C,semi,%3B', + ';keys=comma,%2C,dot,.,semi,%3B' + ], + '{;keys*}' => [ + ';semi=%3B;dot=.;comma=%2C', + ';dot=.;semi=%3B;comma=%2C', + ';comma=%2C;semi=%3B;dot=.', + ';semi=%3B;comma=%2C;dot=.', + ';dot=.;comma=%2C;semi=%3B', + ';comma=%2C;dot=.;semi=%3B' + ] + } + end + context "form query expansion (?)" do + it_behaves_like 'expands', { + '{?who}' => '?who=fred', + '{?half}' => '?half=50%25', + '{?x,y}' => '?x=1024&y=768', + '{?x,y,empty}' => '?x=1024&y=768&empty=', + '{?x,y,undef}' => '?x=1024&y=768', + '{?var:3}' => '?var=val', + '{?list}' => '?list=red,green,blue', + '{?list*}' => '?list=red&list=green&list=blue', + '{?keys}' => [ + '?keys=semi,%3B,dot,.,comma,%2C', + '?keys=dot,.,semi,%3B,comma,%2C', + '?keys=comma,%2C,semi,%3B,dot,.', + '?keys=semi,%3B,comma,%2C,dot,.', + '?keys=dot,.,comma,%2C,semi,%3B', + '?keys=comma,%2C,dot,.,semi,%3B' + ], + '{?keys*}' => [ + '?semi=%3B&dot=.&comma=%2C', + '?dot=.&semi=%3B&comma=%2C', + '?comma=%2C&semi=%3B&dot=.', + '?semi=%3B&comma=%2C&dot=.', + '?dot=.&comma=%2C&semi=%3B', + '?comma=%2C&dot=.&semi=%3B' + ] + } + end + context "form query expansion (&)" do + it_behaves_like 'expands', { + '{&who}' => '&who=fred', + '{&half}' => '&half=50%25', + '?fixed=yes{&x}' => '?fixed=yes&x=1024', + '{&x,y,empty}' => '&x=1024&y=768&empty=', + '{&x,y,undef}' => '&x=1024&y=768', + '{&var:3}' => '&var=val', + '{&list}' => '&list=red,green,blue', + '{&list*}' => '&list=red&list=green&list=blue', + '{&keys}' => [ + '&keys=semi,%3B,dot,.,comma,%2C', + '&keys=dot,.,semi,%3B,comma,%2C', + '&keys=comma,%2C,semi,%3B,dot,.', + '&keys=semi,%3B,comma,%2C,dot,.', + '&keys=dot,.,comma,%2C,semi,%3B', + '&keys=comma,%2C,dot,.,semi,%3B' + ], + '{&keys*}' => [ + '&semi=%3B&dot=.&comma=%2C', + '&dot=.&semi=%3B&comma=%2C', + '&comma=%2C&semi=%3B&dot=.', + '&semi=%3B&comma=%2C&dot=.', + '&dot=.&comma=%2C&semi=%3B', + '&comma=%2C&dot=.&semi=%3B' + ] + } + end +end + +class ExampleTwoProcessor + def self.restore(name, value) + return value.gsub(/-/, " ") if name == "query" + return value + end + + def self.match(name) + return ".*?" if name == "first" + return ".*" + end + def self.validate(name, value) + return !!(value =~ /^[\w ]+$/) if name == "query" + return true + end + + def self.transform(name, value) + return value.gsub(/ /, "+") if name == "query" + return value + end +end + +class DumbProcessor + def self.match(name) + return ".*?" if name == "first" + end +end + +describe Addressable::Template do + describe "Matching" do + let(:uri){ + Addressable::URI.parse( + "http://example.com/search/an-example-search-query/" + ) + } + let(:uri2){ + Addressable::URI.parse("http://example.com/a/b/c/") + } + let(:uri3){ + Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo") + } + let(:uri4){ + Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo") + } + let(:uri5){ + "http://example.com/foo" + } + context "first uri with ExampleTwoProcessor" do + subject { + match = Addressable::Template.new( + "http://example.com/search/{query}/" + ).match(uri, ExampleTwoProcessor) + } + its(:variables){ should == ["query"] } + its(:captures){ should == ["an example search query"] } + end + + context "second uri with ExampleTwoProcessor" do + subject { + match = Addressable::Template.new( + "http://example.com/{first}/{+second}/" + ).match(uri2, ExampleTwoProcessor) + } + its(:variables){ should == ["first", "second"] } + its(:captures){ should == ["a", "b/c"] } + end + + context "second uri with DumbProcessor" do + subject { + match = Addressable::Template.new( + "http://example.com/{first}/{+second}/" + ).match(uri2, DumbProcessor) + } + its(:variables){ should == ["first", "second"] } + its(:captures){ should == ["a", "b/c"] } + end + + context "second uri" do + subject { + match = Addressable::Template.new( + "http://example.com/{first}{/second*}/" + ).match(uri2) + } + its(:variables){ should == ["first", "second"] } + its(:captures){ should == ["a", ["b","c"]] } + end + context "third uri" do + subject { + match = Addressable::Template.new( + "http://example.com/{;hash*,first}" + ).match(uri3) + } + its(:variables){ should == ["hash", "first"] } + its(:captures){ should == [ + {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] } + end + # Note that this expansion is impossible to revert deterministically - the + # * operator means first could have been a key of hash or a separate key. + # Semantically, a separate key is more likely, but both are possible. + context "fourth uri" do + subject { + match = Addressable::Template.new( + "http://example.com/{?hash*,first}" + ).match(uri4) + } + its(:variables){ should == ["hash", "first"] } + its(:captures){ should == [ + {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] } + end + context "fifth uri" do + subject { + match = Addressable::Template.new( + "http://example.com/{path}{?hash*,first}" + ).match(uri5) + } + its(:variables){ should == ["path", "hash", "first"] } + its(:captures){ should == ["foo", nil, nil] } + end + end + describe "extract" do + let(:template) { + Addressable::Template.new( + "http://{host}{/segments*}/{?one,two,bogus}{#fragment}" + ) + } + let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" } + let(:uri2){ "http://example.com/a/b/c/#foo" } + it "should be able to extract with queries" do + template.extract(uri).should == { + "host" => "example.com", + "segments" => %w(a b c), + "one" => "1", + "bogus" => nil, + "two" => "2", + "fragment" => "foo" + } + end + it "should be able to extract without queries" do + template.extract(uri2).should == { + "host" => "example.com", + "segments" => %w(a b c), + "one" => nil, + "bogus" => nil, + "two" => nil, + "fragment" => "foo" + } + end + + context "issue #137" do + subject { Addressable::Template.new('/path{?page,per_page}') } + + it "can match empty" do + data = subject.extract("/path") + data["page"].should == nil + data["per_page"].should == nil + data.keys.sort.should == ['page', 'per_page'] + end + + it "can match first var" do + data = subject.extract("/path?page=1") + data["page"].should == "1" + data["per_page"].should == nil + data.keys.sort.should == ['page', 'per_page'] + end + + it "can match second var" do + data = subject.extract("/path?per_page=1") + data["page"].should == nil + data["per_page"].should == "1" + data.keys.sort.should == ['page', 'per_page'] + end + + it "can match both vars" do + data = subject.extract("/path?page=2&per_page=1") + data["page"].should == "2" + data["per_page"].should == "1" + data.keys.sort.should == ['page', 'per_page'] + end + end + end + + describe "Partial expand with symbols" do + context "partial_expand with two simple values" do + subject { + Addressable::Template.new("http://example.com/{one}/{two}/") + } + it "builds a new pattern" do + subject.partial_expand(:one => "1").pattern.should == + "http://example.com/1/{two}/" + end + end + context "partial_expand query with missing param in middle" do + subject { + Addressable::Template.new("http://example.com/{?one,two,three}/") + } + it "builds a new pattern" do + subject.partial_expand(:one => "1", :three => "3").pattern.should == + "http://example.com/?one=1{&two}&three=3/" + end + end + context "partial_expand with query string" do + subject { + Addressable::Template.new("http://example.com/{?two,one}/") + } + it "builds a new pattern" do + subject.partial_expand(:one => "1").pattern.should == + "http://example.com/{?two}&one=1/" + end + end + context "partial_expand with path operator" do + subject { + Addressable::Template.new("http://example.com{/one,two}/") + } + it "builds a new pattern" do + subject.partial_expand(:one => "1").pattern.should == + "http://example.com/1{/two}/" + end + end + end + describe "Partial expand with strings" do + context "partial_expand with two simple values" do + subject { + Addressable::Template.new("http://example.com/{one}/{two}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1").pattern.should == + "http://example.com/1/{two}/" + end + end + context "partial_expand query with missing param in middle" do + subject { + Addressable::Template.new("http://example.com/{?one,two,three}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1", "three" => "3").pattern.should == + "http://example.com/?one=1{&two}&three=3/" + end + end + context "partial_expand with query string" do + subject { + Addressable::Template.new("http://example.com/{?two,one}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1").pattern.should == + "http://example.com/{?two}&one=1/" + end + end + context "partial_expand with path operator" do + subject { + Addressable::Template.new("http://example.com{/one,two}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1").pattern.should == + "http://example.com/1{/two}/" + end + end + end + describe "Expand" do + context "expand with a processor" do + subject { + Addressable::Template.new("http://example.com/search/{query}/") + } + it "processes spaces" do + subject.expand({"query" => "an example search query"}, + ExampleTwoProcessor).to_str.should == + "http://example.com/search/an+example+search+query/" + end + it "validates" do + lambda{ + subject.expand({"query" => "Bogus!"}, + ExampleTwoProcessor).to_str + }.should raise_error(Addressable::Template::InvalidTemplateValueError) + end + end + context "partial_expand query with missing param in middle" do + subject { + Addressable::Template.new("http://example.com/{?one,two,three}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1", "three" => "3").pattern.should == + "http://example.com/?one=1{&two}&three=3/" + end + end + context "partial_expand with query string" do + subject { + Addressable::Template.new("http://example.com/{?two,one}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1").pattern.should == + "http://example.com/{?two}&one=1/" + end + end + context "partial_expand with path operator" do + subject { + Addressable::Template.new("http://example.com{/one,two}/") + } + it "builds a new pattern" do + subject.partial_expand("one" => "1").pattern.should == + "http://example.com/1{/two}/" + end + end + end + context "Matching with operators" do + describe "Level 1:" do + subject { Addressable::Template.new("foo{foo}/{bar}baz") } + it "can match" do + data = subject.match("foofoo/bananabaz") + data.mapping["foo"].should == "foo" + data.mapping["bar"].should == "banana" + end + it "can fail" do + subject.match("bar/foo").should be_nil + subject.match("foobaz").should be_nil + end + it "can match empty" do + data = subject.match("foo/baz") + data.mapping["foo"].should == nil + data.mapping["bar"].should == nil + end + it "lists vars" do + subject.variables.should == ["foo", "bar"] + end + end + + describe "Level 2:" do + subject { Addressable::Template.new("foo{+foo}{#bar}baz") } + it "can match" do + data = subject.match("foo/test/banana#bazbaz") + data.mapping["foo"].should == "/test/banana" + data.mapping["bar"].should == "baz" + end + it "can match empty level 2 #" do + data = subject.match("foo/test/bananabaz") + data.mapping["foo"].should == "/test/banana" + data.mapping["bar"].should == nil + data = subject.match("foo/test/banana#baz") + data.mapping["foo"].should == "/test/banana" + data.mapping["bar"].should == "" + end + it "can match empty level 2 +" do + data = subject.match("foobaz") + data.mapping["foo"].should == nil + data.mapping["bar"].should == nil + data = subject.match("foo#barbaz") + data.mapping["foo"].should == nil + data.mapping["bar"].should == "bar" + end + it "lists vars" do + subject.variables.should == ["foo", "bar"] + end + end + + describe "Level 3:" do + context "no operator" do + subject { Addressable::Template.new("foo{foo,bar}baz") } + it "can match" do + data = subject.match("foofoo,barbaz") + data.mapping["foo"].should == "foo" + data.mapping["bar"].should == "bar" + end + it "lists vars" do + subject.variables.should == ["foo", "bar"] + end + end + context "+ operator" do + subject { Addressable::Template.new("foo{+foo,bar}baz") } + it "can match" do + data = subject.match("foofoo/bar,barbaz") + data.mapping["bar"].should == "foo/bar,bar" + data.mapping["foo"].should == "" + end + it "lists vars" do + subject.variables.should == ["foo", "bar"] + end + end + context ". operator" do + subject { Addressable::Template.new("foo{.foo,bar}baz") } + it "can match" do + data = subject.match("foo.foo.barbaz") + data.mapping["foo"].should == "foo" + data.mapping["bar"].should == "bar" + end + it "lists vars" do + subject.variables.should == ["foo", "bar"] + end + end + context "/ operator" do + subject { Addressable::Template.new("foo{/foo,bar}baz") } + it "can match" do + data = subject.match("foo/foo/barbaz") + data.mapping["foo"].should == "foo" + data.mapping["bar"].should == "bar" + end + it "lists vars" do + subject.variables.should == ["foo", "bar"] + end + end + context "; operator" do + subject { Addressable::Template.new("foo{;foo,bar,baz}baz") } + it "can match" do + data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz") + data.mapping["foo"].should == "bar baz" + data.mapping["bar"].should == "foo" + data.mapping["baz"].should == "" + end + it "lists vars" do + subject.variables.should == %w(foo bar baz) + end + end + context "? operator" do + context "test" do + subject { Addressable::Template.new("foo{?foo,bar}baz") } + it "can match" do + data = subject.match("foo?foo=bar%20baz&bar=foobaz") + data.mapping["foo"].should == "bar baz" + data.mapping["bar"].should == "foo" + end + it "lists vars" do + subject.variables.should == %w(foo bar) + end + end + + context "issue #137" do + subject { Addressable::Template.new('/path{?page,per_page}') } + + it "can match empty" do + data = subject.match("/path") + data.mapping["page"].should == nil + data.mapping["per_page"].should == nil + data.mapping.keys.sort.should == ['page', 'per_page'] + end + + it "can match first var" do + data = subject.match("/path?page=1") + data.mapping["page"].should == "1" + data.mapping["per_page"].should == nil + data.mapping.keys.sort.should == ['page', 'per_page'] + end + + it "can match second var" do + data = subject.match("/path?per_page=1") + data.mapping["page"].should == nil + data.mapping["per_page"].should == "1" + data.mapping.keys.sort.should == ['page', 'per_page'] + end + + it "can match both vars" do + data = subject.match("/path?page=2&per_page=1") + data.mapping["page"].should == "2" + data.mapping["per_page"].should == "1" + data.mapping.keys.sort.should == ['page', 'per_page'] + end + end + + context "issue #71" do + subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") } + it "can match" do + data = subject.match("http://cyberscore.dev/api/users?username=foobaz") + data.mapping["username"].should == "foobaz" + end + it "lists vars" do + subject.variables.should == %w(username) + subject.keys.should == %w(username) + end + end + end + context "& operator" do + subject { Addressable::Template.new("foo{&foo,bar}baz") } + it "can match" do + data = subject.match("foo&foo=bar%20baz&bar=foobaz") + data.mapping["foo"].should == "bar baz" + data.mapping["bar"].should == "foo" + end + it "lists vars" do + subject.variables.should == %w(foo bar) + end + end + end + end + + context "support regexes:" do + context "EXPRESSION" do + subject { Addressable::Template::EXPRESSION } + it "should be able to match an expression" do + subject.should match("{foo}") + subject.should match("{foo,9}") + subject.should match("{foo.bar,baz}") + subject.should match("{+foo.bar,baz}") + subject.should match("{foo,foo%20bar}") + subject.should match("{#foo:20,baz*}") + subject.should match("stuff{#foo:20,baz*}things") + end + it "should fail on non vars" do + subject.should_not match("!{foo") + subject.should_not match("{foo.bar.}") + subject.should_not match("!{}") + end + end + context "VARNAME" do + subject { Addressable::Template::VARNAME } + it "should be able to match a variable" do + subject.should match("foo") + subject.should match("9") + subject.should match("foo.bar") + subject.should match("foo_bar") + subject.should match("foo_bar.baz") + subject.should match("foo%20bar") + subject.should match("foo%20bar.baz") + end + it "should fail on non vars" do + subject.should_not match("!foo") + subject.should_not match("foo.bar.") + subject.should_not match("foo%2%00bar") + subject.should_not match("foo_ba%r") + subject.should_not match("foo_bar*") + subject.should_not match("foo_bar:20") + end + end + context "VARIABLE_LIST" do + subject { Addressable::Template::VARIABLE_LIST } + it "should be able to match a variable list" do + subject.should match("foo,bar") + subject.should match("foo") + subject.should match("foo,bar*,baz") + subject.should match("foo.bar,bar_baz*,baz:12") + end + it "should fail on non vars" do + subject.should_not match(",foo,bar*,baz") + subject.should_not match("foo,*bar,baz") + subject.should_not match("foo,,bar*,baz") + end + end + context "VARSPEC" do + subject { Addressable::Template::VARSPEC } + it "should be able to match a variable with modifier" do + subject.should match("9:8") + subject.should match("foo.bar*") + subject.should match("foo_bar:12") + subject.should match("foo_bar.baz*") + subject.should match("foo%20bar:12") + subject.should match("foo%20bar.baz*") + end + it "should fail on non vars" do + subject.should_not match("!foo") + subject.should_not match("*foo") + subject.should_not match("fo*o") + subject.should_not match("fo:o") + subject.should_not match("foo:") + end + end + end +end + +describe Addressable::Template::MatchData do + let(:template) { Addressable::Template.new('{foo}/{bar}') } + subject(:its) { template.match('ab/cd') } + its(:uri) { should == Addressable::URI.parse('ab/cd') } + its(:template) { should == template } + its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } } + its(:variables) { should == ['foo', 'bar'] } + its(:keys) { should == ['foo', 'bar'] } + its(:names) { should == ['foo', 'bar'] } + its(:values) { should == ['ab', 'cd'] } + its(:captures) { should == ['ab', 'cd'] } + its(:to_a) { should == ['ab/cd', 'ab', 'cd'] } + its(:to_s) { should == 'ab/cd' } + its(:string) { should == its.to_s } + its(:pre_match) { should == "" } + its(:post_match) { should == "" } + + describe 'values_at' do + it 'returns an array with the values' do + its.values_at(0, 2).should == ['ab/cd', 'cd'] + end + it 'allows mixing integer an string keys' do + its.values_at('foo', 1).should == ['ab', 'ab'] + end + it 'accepts unknown keys' do + its.values_at('baz', 'foo').should == [nil, 'ab'] + end + end + + describe '[]' do + context 'string key' do + it 'returns the corresponding capture' do + its['foo'].should == 'ab' + its['bar'].should == 'cd' + end + it 'returns nil for unknown keys' do + its['baz'].should be_nil + end + end + context 'symbol key' do + it 'returns the corresponding capture' do + its[:foo].should == 'ab' + its[:bar].should == 'cd' + end + it 'returns nil for unknown keys' do + its[:baz].should be_nil + end + end + context 'integer key' do + it 'returns the full URI for index 0' do + its[0].should == 'ab/cd' + end + it 'returns the corresponding capture' do + its[1].should == 'ab' + its[2].should == 'cd' + end + it 'returns nil for unknown keys' do + its[3].should be_nil + end + end + context 'other key' do + it 'raises an exception' do + expect { its[Object.new] }.to raise_error(TypeError) + end + end + context 'with length' do + it 'returns an array starting at index with given length' do + its[0, 2].should == ['ab/cd', 'ab'] + its[2, 1].should == ['cd'] + end + end + end +end diff --git a/.gems/gems/addressable-2.3.6/spec/addressable/uri_spec.rb b/.gems/gems/addressable-2.3.6/spec/addressable/uri_spec.rb new file mode 100644 index 0000000..ee45124 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/spec/addressable/uri_spec.rb @@ -0,0 +1,5940 @@ +# coding: utf-8 +# Copyright (C) 2006-2013 Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "addressable/uri" +require "uri" + +if !"".respond_to?("force_encoding") + class String + def force_encoding(encoding) + @encoding = encoding + end + + def encoding + @encoding ||= Encoding::ASCII_8BIT + end + end + + class Encoding + def initialize(name) + @name = name + end + + def to_s + return @name + end + + UTF_8 = Encoding.new("UTF-8") + ASCII_8BIT = Encoding.new("US-ASCII") + end +end + +module Fake + module URI + class HTTP + def initialize(uri) + @uri = uri + end + + def to_s + return @uri.to_s + end + + alias :to_str :to_s + end + end +end + +describe Addressable::URI, "when created with a non-numeric port number" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:port => "bogus") + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with a non-string scheme" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:scheme => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string user" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:user => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string password" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:password => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string userinfo" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:userinfo => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string host" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:host => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string authority" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:authority => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string authority" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:authority => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string path" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:path => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string query" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:query => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string fragment" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:fragment => :bogus) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a scheme but no hierarchical " + + "segment" do + it "should raise an error" do + (lambda do + Addressable::URI.parse("http:") + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with an invalid host" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:host => "") + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created from nil components" do + before do + @uri = Addressable::URI.new + end + + it "should have a nil site value" do + @uri.site.should == nil + end + + it "should have an empty path" do + @uri.path.should == "" + end + + it "should be an empty uri" do + @uri.to_s.should == "" + end + + it "should have a nil default port" do + @uri.default_port.should == nil + end + + it "should be empty" do + @uri.should be_empty + end + + it "should raise an error if the scheme is set to whitespace" do + (lambda do + @uri.scheme = "\t \n" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if the scheme is set to all digits" do + (lambda do + @uri.scheme = "123" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + (lambda do + @uri.user = "user" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + (lambda do + @uri.password = "pass" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + (lambda do + @uri.scheme = "http" + @uri.fragment = "fragment" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + (lambda do + @uri.fragment = "fragment" + @uri.scheme = "http" + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when initialized from individual components" do + before do + @uri = Addressable::URI.new( + :scheme => "http", + :user => "user", + :password => "password", + :host => "example.com", + :port => 8080, + :path => "/path", + :query => "query=value", + :fragment => "fragment" + ) + end + + it "returns 'http' for #scheme" do + @uri.scheme.should == "http" + end + + it "returns 'http' for #normalized_scheme" do + @uri.normalized_scheme.should == "http" + end + + it "returns 'user' for #user" do + @uri.user.should == "user" + end + + it "returns 'user' for #normalized_user" do + @uri.normalized_user.should == "user" + end + + it "returns 'password' for #password" do + @uri.password.should == "password" + end + + it "returns 'password' for #normalized_password" do + @uri.normalized_password.should == "password" + end + + it "returns 'user:password' for #userinfo" do + @uri.userinfo.should == "user:password" + end + + it "returns 'user:password' for #normalized_userinfo" do + @uri.normalized_userinfo.should == "user:password" + end + + it "returns 'example.com' for #host" do + @uri.host.should == "example.com" + end + + it "returns 'example.com' for #normalized_host" do + @uri.normalized_host.should == "example.com" + end + + it "returns 'user:password@example.com:8080' for #authority" do + @uri.authority.should == "user:password@example.com:8080" + end + + it "returns 'user:password@example.com:8080' for #normalized_authority" do + @uri.normalized_authority.should == "user:password@example.com:8080" + end + + it "returns 8080 for #port" do + @uri.port.should == 8080 + end + + it "returns 8080 for #normalized_port" do + @uri.normalized_port.should == 8080 + end + + it "returns 80 for #default_port" do + @uri.default_port.should == 80 + end + + it "returns 'http://user:password@example.com:8080' for #site" do + @uri.site.should == "http://user:password@example.com:8080" + end + + it "returns 'http://user:password@example.com:8080' for #normalized_site" do + @uri.normalized_site.should == "http://user:password@example.com:8080" + end + + it "returns '/path' for #path" do + @uri.path.should == "/path" + end + + it "returns '/path' for #normalized_path" do + @uri.normalized_path.should == "/path" + end + + it "returns 'query=value' for #query" do + @uri.query.should == "query=value" + end + + it "returns 'query=value' for #normalized_query" do + @uri.normalized_query.should == "query=value" + end + + it "returns 'fragment' for #fragment" do + @uri.fragment.should == "fragment" + end + + it "returns 'fragment' for #normalized_fragment" do + @uri.normalized_fragment.should == "fragment" + end + + it "returns #hash" do + @uri.hash.should_not be nil + end + + it "returns #to_s" do + @uri.to_s.should == + "http://user:password@example.com:8080/path?query=value#fragment" + end + + it "should not be empty" do + @uri.should_not be_empty + end + + it "should not be frozen" do + @uri.should_not be_frozen + end + + it "should allow destructive operations" do + expect { @uri.normalize! }.not_to raise_error + end +end + +describe Addressable::URI, "when initialized from " + + "frozen individual components" do + before do + @uri = Addressable::URI.new( + :scheme => "http".freeze, + :user => "user".freeze, + :password => "password".freeze, + :host => "example.com".freeze, + :port => "8080".freeze, + :path => "/path".freeze, + :query => "query=value".freeze, + :fragment => "fragment".freeze + ) + end + + it "returns 'http' for #scheme" do + @uri.scheme.should == "http" + end + + it "returns 'http' for #normalized_scheme" do + @uri.normalized_scheme.should == "http" + end + + it "returns 'user' for #user" do + @uri.user.should == "user" + end + + it "returns 'user' for #normalized_user" do + @uri.normalized_user.should == "user" + end + + it "returns 'password' for #password" do + @uri.password.should == "password" + end + + it "returns 'password' for #normalized_password" do + @uri.normalized_password.should == "password" + end + + it "returns 'user:password' for #userinfo" do + @uri.userinfo.should == "user:password" + end + + it "returns 'user:password' for #normalized_userinfo" do + @uri.normalized_userinfo.should == "user:password" + end + + it "returns 'example.com' for #host" do + @uri.host.should == "example.com" + end + + it "returns 'example.com' for #normalized_host" do + @uri.normalized_host.should == "example.com" + end + + it "returns 'user:password@example.com:8080' for #authority" do + @uri.authority.should == "user:password@example.com:8080" + end + + it "returns 'user:password@example.com:8080' for #normalized_authority" do + @uri.normalized_authority.should == "user:password@example.com:8080" + end + + it "returns 8080 for #port" do + @uri.port.should == 8080 + end + + it "returns 8080 for #normalized_port" do + @uri.normalized_port.should == 8080 + end + + it "returns 80 for #default_port" do + @uri.default_port.should == 80 + end + + it "returns 'http://user:password@example.com:8080' for #site" do + @uri.site.should == "http://user:password@example.com:8080" + end + + it "returns 'http://user:password@example.com:8080' for #normalized_site" do + @uri.normalized_site.should == "http://user:password@example.com:8080" + end + + it "returns '/path' for #path" do + @uri.path.should == "/path" + end + + it "returns '/path' for #normalized_path" do + @uri.normalized_path.should == "/path" + end + + it "returns 'query=value' for #query" do + @uri.query.should == "query=value" + end + + it "returns 'query=value' for #normalized_query" do + @uri.normalized_query.should == "query=value" + end + + it "returns 'fragment' for #fragment" do + @uri.fragment.should == "fragment" + end + + it "returns 'fragment' for #normalized_fragment" do + @uri.normalized_fragment.should == "fragment" + end + + it "returns #hash" do + @uri.hash.should_not be nil + end + + it "returns #to_s" do + @uri.to_s.should == + "http://user:password@example.com:8080/path?query=value#fragment" + end + + it "should not be empty" do + @uri.should_not be_empty + end + + it "should not be frozen" do + @uri.should_not be_frozen + end + + it "should allow destructive operations" do + expect { @uri.normalize! }.not_to raise_error + end +end + +describe Addressable::URI, "when parsed from a frozen string" do + before do + @uri = Addressable::URI.parse( + "http://user:password@example.com:8080/path?query=value#fragment".freeze + ) + end + + it "returns 'http' for #scheme" do + @uri.scheme.should == "http" + end + + it "returns 'http' for #normalized_scheme" do + @uri.normalized_scheme.should == "http" + end + + it "returns 'user' for #user" do + @uri.user.should == "user" + end + + it "returns 'user' for #normalized_user" do + @uri.normalized_user.should == "user" + end + + it "returns 'password' for #password" do + @uri.password.should == "password" + end + + it "returns 'password' for #normalized_password" do + @uri.normalized_password.should == "password" + end + + it "returns 'user:password' for #userinfo" do + @uri.userinfo.should == "user:password" + end + + it "returns 'user:password' for #normalized_userinfo" do + @uri.normalized_userinfo.should == "user:password" + end + + it "returns 'example.com' for #host" do + @uri.host.should == "example.com" + end + + it "returns 'example.com' for #normalized_host" do + @uri.normalized_host.should == "example.com" + end + + it "returns 'user:password@example.com:8080' for #authority" do + @uri.authority.should == "user:password@example.com:8080" + end + + it "returns 'user:password@example.com:8080' for #normalized_authority" do + @uri.normalized_authority.should == "user:password@example.com:8080" + end + + it "returns 8080 for #port" do + @uri.port.should == 8080 + end + + it "returns 8080 for #normalized_port" do + @uri.normalized_port.should == 8080 + end + + it "returns 80 for #default_port" do + @uri.default_port.should == 80 + end + + it "returns 'http://user:password@example.com:8080' for #site" do + @uri.site.should == "http://user:password@example.com:8080" + end + + it "returns 'http://user:password@example.com:8080' for #normalized_site" do + @uri.normalized_site.should == "http://user:password@example.com:8080" + end + + it "returns '/path' for #path" do + @uri.path.should == "/path" + end + + it "returns '/path' for #normalized_path" do + @uri.normalized_path.should == "/path" + end + + it "returns 'query=value' for #query" do + @uri.query.should == "query=value" + end + + it "returns 'query=value' for #normalized_query" do + @uri.normalized_query.should == "query=value" + end + + it "returns 'fragment' for #fragment" do + @uri.fragment.should == "fragment" + end + + it "returns 'fragment' for #normalized_fragment" do + @uri.normalized_fragment.should == "fragment" + end + + it "returns #hash" do + @uri.hash.should_not be nil + end + + it "returns #to_s" do + @uri.to_s.should == + "http://user:password@example.com:8080/path?query=value#fragment" + end + + it "should not be empty" do + @uri.should_not be_empty + end + + it "should not be frozen" do + @uri.should_not be_frozen + end + + it "should allow destructive operations" do + expect { @uri.normalize! }.not_to raise_error + end +end + +describe Addressable::URI, "when frozen" do + before do + @uri = Addressable::URI.new.freeze + end + + it "returns nil for #scheme" do + @uri.scheme.should == nil + end + + it "returns nil for #normalized_scheme" do + @uri.normalized_scheme.should == nil + end + + it "returns nil for #user" do + @uri.user.should == nil + end + + it "returns nil for #normalized_user" do + @uri.normalized_user.should == nil + end + + it "returns nil for #password" do + @uri.password.should == nil + end + + it "returns nil for #normalized_password" do + @uri.normalized_password.should == nil + end + + it "returns nil for #userinfo" do + @uri.userinfo.should == nil + end + + it "returns nil for #normalized_userinfo" do + @uri.normalized_userinfo.should == nil + end + + it "returns nil for #host" do + @uri.host.should == nil + end + + it "returns nil for #normalized_host" do + @uri.normalized_host.should == nil + end + + it "returns nil for #authority" do + @uri.authority.should == nil + end + + it "returns nil for #normalized_authority" do + @uri.normalized_authority.should == nil + end + + it "returns nil for #port" do + @uri.port.should == nil + end + + it "returns nil for #normalized_port" do + @uri.normalized_port.should == nil + end + + it "returns nil for #default_port" do + @uri.default_port.should == nil + end + + it "returns nil for #site" do + @uri.site.should == nil + end + + it "returns nil for #normalized_site" do + @uri.normalized_site.should == nil + end + + it "returns '' for #path" do + @uri.path.should == '' + end + + it "returns '' for #normalized_path" do + @uri.normalized_path.should == '' + end + + it "returns nil for #query" do + @uri.query.should == nil + end + + it "returns nil for #normalized_query" do + @uri.normalized_query.should == nil + end + + it "returns nil for #fragment" do + @uri.fragment.should == nil + end + + it "returns nil for #normalized_fragment" do + @uri.normalized_fragment.should == nil + end + + it "returns #hash" do + @uri.hash.should_not be nil + end + + it "returns #to_s" do + @uri.to_s.should == '' + end + + it "should be empty" do + @uri.should be_empty + end + + it "should be frozen" do + @uri.should be_frozen + end + + it "should not be frozen after duping" do + @uri.dup.should_not be_frozen + end + + it "should not allow destructive operations" do + expect { @uri.normalize! }.to raise_error { |error| + error.message.should match(/can't modify frozen/) + error.should satisfy { |e| RuntimeError === e || TypeError === e } + } + end +end + +describe Addressable::URI, "when frozen" do + before do + @uri = Addressable::URI.parse( + "HTTP://example.com.:%38%30/%70a%74%68?a=%31#1%323" + ).freeze + end + + it "returns 'HTTP' for #scheme" do + @uri.scheme.should == "HTTP" + end + + it "returns 'http' for #normalized_scheme" do + @uri.normalized_scheme.should == "http" + @uri.normalize.scheme.should == "http" + end + + it "returns nil for #user" do + @uri.user.should == nil + end + + it "returns nil for #normalized_user" do + @uri.normalized_user.should == nil + end + + it "returns nil for #password" do + @uri.password.should == nil + end + + it "returns nil for #normalized_password" do + @uri.normalized_password.should == nil + end + + it "returns nil for #userinfo" do + @uri.userinfo.should == nil + end + + it "returns nil for #normalized_userinfo" do + @uri.normalized_userinfo.should == nil + end + + it "returns 'example.com.' for #host" do + @uri.host.should == "example.com." + end + + it "returns nil for #normalized_host" do + @uri.normalized_host.should == "example.com" + @uri.normalize.host.should == "example.com" + end + + it "returns 'example.com.:80' for #authority" do + @uri.authority.should == "example.com.:80" + end + + it "returns 'example.com:80' for #normalized_authority" do + @uri.normalized_authority.should == "example.com" + @uri.normalize.authority.should == "example.com" + end + + it "returns 80 for #port" do + @uri.port.should == 80 + end + + it "returns nil for #normalized_port" do + @uri.normalized_port.should == nil + @uri.normalize.port.should == nil + end + + it "returns 80 for #default_port" do + @uri.default_port.should == 80 + end + + it "returns 'HTTP://example.com.:80' for #site" do + @uri.site.should == "HTTP://example.com.:80" + end + + it "returns 'http://example.com' for #normalized_site" do + @uri.normalized_site.should == "http://example.com" + @uri.normalize.site.should == "http://example.com" + end + + it "returns '/%70a%74%68' for #path" do + @uri.path.should == "/%70a%74%68" + end + + it "returns '/path' for #normalized_path" do + @uri.normalized_path.should == "/path" + @uri.normalize.path.should == "/path" + end + + it "returns 'a=%31' for #query" do + @uri.query.should == "a=%31" + end + + it "returns 'a=1' for #normalized_query" do + @uri.normalized_query.should == "a=1" + @uri.normalize.query.should == "a=1" + end + + it "returns '1%323' for #fragment" do + @uri.fragment.should == "1%323" + end + + it "returns '123' for #normalized_fragment" do + @uri.normalized_fragment.should == "123" + @uri.normalize.fragment.should == "123" + end + + it "returns #hash" do + @uri.hash.should_not be nil + end + + it "returns #to_s" do + @uri.to_s.should == 'HTTP://example.com.:80/%70a%74%68?a=%31#1%323' + @uri.normalize.to_s.should == 'http://example.com/path?a=1#123' + end + + it "should not be empty" do + @uri.should_not be_empty + end + + it "should be frozen" do + @uri.should be_frozen + end + + it "should not be frozen after duping" do + @uri.dup.should_not be_frozen + end + + it "should not allow destructive operations" do + expect { @uri.normalize! }.to raise_error { |error| + error.message.should match(/can't modify frozen/) + error.should satisfy { |e| RuntimeError === e || TypeError === e } + } + end +end + +describe Addressable::URI, "when created from string components" do + before do + @uri = Addressable::URI.new( + :scheme => "http", :host => "example.com" + ) + end + + it "should have a site value of 'http://example.com'" do + @uri.site.should == "http://example.com" + end + + it "should be equal to the equivalent parsed URI" do + @uri.should == Addressable::URI.parse("http://example.com") + end + + it "should raise an error if invalid components omitted" do + (lambda do + @uri.omit(:bogus) + end).should raise_error(ArgumentError) + (lambda do + @uri.omit(:scheme, :bogus, :path) + end).should raise_error(ArgumentError) + end +end + +describe Addressable::URI, "when created with a nil host but " + + "non-nil authority components" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:user => "user", :password => "pass", :port => 80) + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with both an authority and a user" do + it "should raise an error" do + (lambda do + Addressable::URI.new( + :user => "user", :authority => "user@example.com:80" + ) + end).should raise_error(ArgumentError) + end +end + +describe Addressable::URI, "when created with an authority and no port" do + before do + @uri = Addressable::URI.new(:authority => "user@example.com") + end + + it "should not infer a port" do + @uri.port.should == nil + @uri.default_port.should == nil + @uri.inferred_port.should == nil + end + + it "should have a site value of '//user@example.com'" do + @uri.site.should == "//user@example.com" + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when created with a host with trailing dots" do + before do + @uri = Addressable::URI.new(:authority => "example...") + end + + it "should have a stable normalized form" do + @uri.normalize.normalize.normalize.host.should == + @uri.normalize.host + end +end + +describe Addressable::URI, "when created with both a userinfo and a user" do + it "should raise an error" do + (lambda do + Addressable::URI.new(:user => "user", :userinfo => "user:pass") + end).should raise_error(ArgumentError) + end +end + +describe Addressable::URI, "when created with a path that hasn't been " + + "prefixed with a '/' but a host specified" do + before do + @uri = Addressable::URI.new( + :scheme => "http", :host => "example.com", :path => "path" + ) + end + + it "should prefix a '/' to the path" do + @uri.should == Addressable::URI.parse("http://example.com/path") + end + + it "should have a site value of 'http://example.com'" do + @uri.site.should == "http://example.com" + end + + it "should have an origin of 'http://example.com" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when created with a path that hasn't been " + + "prefixed with a '/' but no host specified" do + before do + @uri = Addressable::URI.new( + :scheme => "http", :path => "path" + ) + end + + it "should not prefix a '/' to the path" do + @uri.should == Addressable::URI.parse("http:path") + end + + it "should have a site value of 'http:'" do + @uri.site.should == "http:" + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from an Addressable::URI object" do + it "should not have unexpected side-effects" do + original_uri = Addressable::URI.parse("http://example.com/") + new_uri = Addressable::URI.parse(original_uri) + new_uri.host = 'www.example.com' + new_uri.host.should == 'www.example.com' + new_uri.to_s.should == 'http://www.example.com/' + original_uri.host.should == 'example.com' + original_uri.to_s.should == 'http://example.com/' + end + + it "should not have unexpected side-effects" do + original_uri = Addressable::URI.parse("http://example.com/") + new_uri = Addressable::URI.heuristic_parse(original_uri) + new_uri.host = 'www.example.com' + new_uri.host.should == 'www.example.com' + new_uri.to_s.should == 'http://www.example.com/' + original_uri.host.should == 'example.com' + original_uri.to_s.should == 'http://example.com/' + end +end + +describe Addressable::URI, "when parsed from something that looks " + + "like a URI object" do + it "should parse without error" do + uri = Addressable::URI.parse(Fake::URI::HTTP.new("http://example.com/")) + (lambda do + Addressable::URI.parse(uri) + end).should_not raise_error + end +end + +describe Addressable::URI, "when parsed from ''" do + before do + @uri = Addressable::URI.parse("") + end + + it "should have no scheme" do + @uri.scheme.should == nil + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should have a path of ''" do + @uri.path.should == "" + end + + it "should have a request URI of '/'" do + @uri.request_uri.should == "/" + end + + it "should be considered relative" do + @uri.should be_relative + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'ftp://ftp.is.co.za/rfc/rfc1808.txt'" do + before do + @uri = Addressable::URI.parse("ftp://ftp.is.co.za/rfc/rfc1808.txt") + end + + it "should use the 'ftp' scheme" do + @uri.scheme.should == "ftp" + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have a host of 'ftp.is.co.za'" do + @uri.host.should == "ftp.is.co.za" + end + + it "should have inferred_port of 21" do + @uri.inferred_port.should == 21 + end + + it "should have a path of '/rfc/rfc1808.txt'" do + @uri.path.should == "/rfc/rfc1808.txt" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have an origin of 'ftp://ftp.is.co.za'" do + @uri.origin.should == 'ftp://ftp.is.co.za' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'http://www.ietf.org/rfc/rfc2396.txt'" do + before do + @uri = Addressable::URI.parse("http://www.ietf.org/rfc/rfc2396.txt") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have a host of 'www.ietf.org'" do + @uri.host.should == "www.ietf.org" + end + + it "should have inferred_port of 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/rfc/rfc2396.txt'" do + @uri.path.should == "/rfc/rfc2396.txt" + end + + it "should have a request URI of '/rfc/rfc2396.txt'" do + @uri.request_uri.should == "/rfc/rfc2396.txt" + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should correctly omit components" do + @uri.omit(:scheme).to_s.should == "//www.ietf.org/rfc/rfc2396.txt" + @uri.omit(:path).to_s.should == "http://www.ietf.org" + end + + it "should correctly omit components destructively" do + @uri.omit!(:scheme) + @uri.to_s.should == "//www.ietf.org/rfc/rfc2396.txt" + end + + it "should have an origin of 'http://www.ietf.org'" do + @uri.origin.should == 'http://www.ietf.org' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'ldap://[2001:db8::7]/c=GB?objectClass?one'" do + before do + @uri = Addressable::URI.parse("ldap://[2001:db8::7]/c=GB?objectClass?one") + end + + it "should use the 'ldap' scheme" do + @uri.scheme.should == "ldap" + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have a host of '[2001:db8::7]'" do + @uri.host.should == "[2001:db8::7]" + end + + it "should have inferred_port of 389" do + @uri.inferred_port.should == 389 + end + + it "should have a path of '/c=GB'" do + @uri.path.should == "/c=GB" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should not allow request URI assignment" do + (lambda do + @uri.request_uri = "/" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should have a query of 'objectClass?one'" do + @uri.query.should == "objectClass?one" + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should correctly omit components" do + @uri.omit(:scheme, :authority).to_s.should == "/c=GB?objectClass?one" + @uri.omit(:path).to_s.should == "ldap://[2001:db8::7]?objectClass?one" + end + + it "should correctly omit components destructively" do + @uri.omit!(:scheme, :authority) + @uri.to_s.should == "/c=GB?objectClass?one" + end + + it "should raise an error if omission would create an invalid URI" do + (lambda do + @uri.omit(:authority, :path) + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should have an origin of 'ldap://[2001:db8::7]'" do + @uri.origin.should == 'ldap://[2001:db8::7]' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'mailto:John.Doe@example.com'" do + before do + @uri = Addressable::URI.parse("mailto:John.Doe@example.com") + end + + it "should use the 'mailto' scheme" do + @uri.scheme.should == "mailto" + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should not have an inferred_port" do + @uri.inferred_port.should == nil + end + + it "should have a path of 'John.Doe@example.com'" do + @uri.path.should == "John.Doe@example.com" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +# Section 2 of RFC 6068 +describe Addressable::URI, "when parsed from " + + "'mailto:?to=addr1@an.example,addr2@an.example'" do + before do + @uri = Addressable::URI.parse( + "mailto:?to=addr1@an.example,addr2@an.example" + ) + end + + it "should use the 'mailto' scheme" do + @uri.scheme.should == "mailto" + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should not have an inferred_port" do + @uri.inferred_port.should == nil + end + + it "should have a path of ''" do + @uri.path.should == "" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should have the To: field value parameterized" do + @uri.query_values(Hash)["to"].should == ( + "addr1@an.example,addr2@an.example" + ) + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'news:comp.infosystems.www.servers.unix'" do + before do + @uri = Addressable::URI.parse("news:comp.infosystems.www.servers.unix") + end + + it "should use the 'news' scheme" do + @uri.scheme.should == "news" + end + + it "should not have an inferred_port" do + @uri.inferred_port.should == nil + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should have a path of 'comp.infosystems.www.servers.unix'" do + @uri.path.should == "comp.infosystems.www.servers.unix" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'tel:+1-816-555-1212'" do + before do + @uri = Addressable::URI.parse("tel:+1-816-555-1212") + end + + it "should use the 'tel' scheme" do + @uri.scheme.should == "tel" + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should not have an inferred_port" do + @uri.inferred_port.should == nil + end + + it "should have a path of '+1-816-555-1212'" do + @uri.path.should == "+1-816-555-1212" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'telnet://192.0.2.16:80/'" do + before do + @uri = Addressable::URI.parse("telnet://192.0.2.16:80/") + end + + it "should use the 'telnet' scheme" do + @uri.scheme.should == "telnet" + end + + it "should have a host of '192.0.2.16'" do + @uri.host.should == "192.0.2.16" + end + + it "should have a port of 80" do + @uri.port.should == 80 + end + + it "should have a inferred_port of 80" do + @uri.inferred_port.should == 80 + end + + it "should have a default_port of 23" do + @uri.default_port.should == 23 + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have a path of '/'" do + @uri.path.should == "/" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have an origin of 'telnet://192.0.2.16:80'" do + @uri.origin.should == 'telnet://192.0.2.16:80' + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'urn:oasis:names:specification:docbook:dtd:xml:4.1.2'" do + before do + @uri = Addressable::URI.parse( + "urn:oasis:names:specification:docbook:dtd:xml:4.1.2") + end + + it "should use the 'urn' scheme" do + @uri.scheme.should == "urn" + end + + it "should not have an inferred_port" do + @uri.inferred_port.should == nil + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should have a path of " + + "'oasis:names:specification:docbook:dtd:xml:4.1.2'" do + @uri.path.should == "oasis:names:specification:docbook:dtd:xml:4.1.2" + end + + it "should not have a request URI" do + @uri.request_uri.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when heuristically parsed from " + + "'192.0.2.16:8000/path'" do + before do + @uri = Addressable::URI.heuristic_parse("192.0.2.16:8000/path") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have a host of '192.0.2.16'" do + @uri.host.should == "192.0.2.16" + end + + it "should have a port of '8000'" do + @uri.port.should == 8000 + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have a path of '/path'" do + @uri.path.should == "/path" + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have an origin of 'http://192.0.2.16:8000'" do + @uri.origin.should == 'http://192.0.2.16:8000' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com'" do + before do + @uri = Addressable::URI.parse("http://example.com") + end + + it "when inspected, should have the correct URI" do + @uri.inspect.should include("http://example.com") + end + + it "when inspected, should have the correct class name" do + @uri.inspect.should include("Addressable::URI") + end + + it "when inspected, should have the correct object id" do + @uri.inspect.should include("%#0x" % @uri.object_id) + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have an authority segment of 'example.com'" do + @uri.authority.should == "example.com" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should be considered ip-based" do + @uri.should be_ip_based + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should not have a specified port" do + @uri.port.should == nil + end + + it "should have an empty path" do + @uri.path.should == "" + end + + it "should have no query string" do + @uri.query.should == nil + @uri.query_values.should == nil + end + + it "should have a request URI of '/'" do + @uri.request_uri.should == "/" + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should be considered absolute" do + @uri.should be_absolute + end + + it "should not be considered relative" do + @uri.should_not be_relative + end + + it "should not be exactly equal to 42" do + @uri.eql?(42).should == false + end + + it "should not be equal to 42" do + (@uri == 42).should == false + end + + it "should not be roughly equal to 42" do + (@uri === 42).should == false + end + + it "should be exactly equal to http://example.com" do + @uri.eql?(Addressable::URI.parse("http://example.com")).should == true + end + + it "should be roughly equal to http://example.com/" do + (@uri === Addressable::URI.parse("http://example.com/")).should == true + end + + it "should be roughly equal to the string 'http://example.com/'" do + (@uri === "http://example.com/").should == true + end + + it "should not be roughly equal to the string " + + "'http://example.com:bogus/'" do + (lambda do + (@uri === "http://example.com:bogus/").should == false + end).should_not raise_error + end + + it "should result in itself when joined with itself" do + @uri.join(@uri).to_s.should == "http://example.com" + @uri.join!(@uri).to_s.should == "http://example.com" + end + + it "should be equivalent to http://EXAMPLE.com" do + @uri.should == Addressable::URI.parse("http://EXAMPLE.com") + end + + it "should be equivalent to http://EXAMPLE.com:80/" do + @uri.should == Addressable::URI.parse("http://EXAMPLE.com:80/") + end + + it "should have the same hash as http://example.com" do + @uri.hash.should == Addressable::URI.parse("http://example.com").hash + end + + it "should have the same hash as http://EXAMPLE.com after assignment" do + @uri.host = "EXAMPLE.com" + @uri.hash.should == Addressable::URI.parse("http://EXAMPLE.com").hash + end + + it "should have a different hash from http://EXAMPLE.com" do + @uri.hash.should_not == Addressable::URI.parse("http://EXAMPLE.com").hash + end + + # Section 6.2.3 of RFC 3986 + it "should be equivalent to http://example.com/" do + @uri.should == Addressable::URI.parse("http://example.com/") + end + + # Section 6.2.3 of RFC 3986 + it "should be equivalent to http://example.com:/" do + @uri.should == Addressable::URI.parse("http://example.com:/") + end + + # Section 6.2.3 of RFC 3986 + it "should be equivalent to http://example.com:80/" do + @uri.should == Addressable::URI.parse("http://example.com:80/") + end + + # Section 6.2.2.1 of RFC 3986 + it "should be equivalent to http://EXAMPLE.COM/" do + @uri.should == Addressable::URI.parse("http://EXAMPLE.COM/") + end + + it "should have a route of '/path/' to 'http://example.com/path/'" do + @uri.route_to("http://example.com/path/").should == + Addressable::URI.parse("/path/") + end + + it "should have a route of '..' from 'http://example.com/path/'" do + @uri.route_from("http://example.com/path/").should == + Addressable::URI.parse("..") + end + + it "should have a route of '#' to 'http://example.com/'" do + @uri.route_to("http://example.com/").should == + Addressable::URI.parse("#") + end + + it "should have a route of 'http://elsewhere.com/' to " + + "'http://elsewhere.com/'" do + @uri.route_to("http://elsewhere.com/").should == + Addressable::URI.parse("http://elsewhere.com/") + end + + it "when joined with 'relative/path' should be " + + "'http://example.com/relative/path'" do + @uri.join('relative/path').should == + Addressable::URI.parse("http://example.com/relative/path") + end + + it "when joined with a bogus object a TypeError should be raised" do + (lambda do + @uri.join(42) + end).should raise_error(TypeError) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password.should == nil + @uri.to_s.should == "http://newuser@example.com" + end + + it "should have the correct username after assignment" do + @uri.user = "user@123!" + @uri.user.should == "user@123!" + @uri.normalized_user.should == "user%40123%21" + @uri.password.should == nil + @uri.normalize.to_s.should == "http://user%40123%21@example.com/" + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.user.should == "" + @uri.to_s.should == "http://:newpass@example.com" + end + + it "should have the correct password after assignment" do + @uri.password = "#secret@123!" + @uri.password.should == "#secret@123!" + @uri.normalized_password.should == "%23secret%40123%21" + @uri.user.should == "" + @uri.normalize.to_s.should == "http://:%23secret%40123%21@example.com/" + @uri.omit(:password).to_s.should == "http://example.com" + end + + it "should have the correct user/pass after repeated assignment" do + @uri.user = nil + @uri.user.should == nil + @uri.password = "newpass" + @uri.password.should == "newpass" + # Username cannot be nil if the password is set + @uri.user.should == "" + @uri.to_s.should == "http://:newpass@example.com" + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password = nil + @uri.password.should == nil + @uri.to_s.should == "http://newuser@example.com" + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password = "" + @uri.password.should == "" + @uri.to_s.should == "http://newuser:@example.com" + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.user = nil + # Username cannot be nil if the password is set + @uri.user.should == "" + @uri.to_s.should == "http://:newpass@example.com" + end + + it "should have the correct user/pass after userinfo assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.userinfo = nil + @uri.userinfo.should == nil + @uri.user.should == nil + @uri.password.should == nil + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +# Section 5.1.2 of RFC 2616 +describe Addressable::URI, "when parsed from " + + "'http://www.w3.org/pub/WWW/TheProject.html'" do + before do + @uri = Addressable::URI.parse("http://www.w3.org/pub/WWW/TheProject.html") + end + + it "should have the correct request URI" do + @uri.request_uri.should == "/pub/WWW/TheProject.html" + end + + it "should have the correct request URI after assignment" do + @uri.request_uri = "/some/where/else.html?query?string" + @uri.request_uri.should == "/some/where/else.html?query?string" + @uri.path.should == "/some/where/else.html" + @uri.query.should == "query?string" + end + + it "should have the correct request URI after assignment" do + @uri.request_uri = "?x=y" + @uri.request_uri.should == "/?x=y" + @uri.path.should == "/" + @uri.query.should == "x=y" + end + + it "should raise an error if the site value is set to something bogus" do + (lambda do + @uri.site = 42 + end).should raise_error(TypeError) + end + + it "should raise an error if the request URI is set to something bogus" do + (lambda do + @uri.request_uri = 42 + end).should raise_error(TypeError) + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "www.w3.org", + :port => nil, + :path => "/pub/WWW/TheProject.html", + :query => nil, + :fragment => nil + } + end + + it "should have an origin of 'http://www.w3.org'" do + @uri.origin.should == 'http://www.w3.org' + end +end + +describe Addressable::URI, "when parsing IPv6 addresses" do + it "should not raise an error for " + + "'http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[fe80:0:0:0:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[fe80:0:0:0:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[fe80::200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[fe80::200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[::1]/'" do + Addressable::URI.parse("http://[::1]/") + end + + it "should not raise an error for " + + "'http://[fe80::1]/'" do + Addressable::URI.parse("http://[fe80::1]/") + end + + it "should raise an error for " + + "'http://[]/'" do + (lambda do + Addressable::URI.parse("http://[]/") + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsing IPv6 address" do + subject { Addressable::URI.parse("http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") } + its(:host) { should == '[3ffe:1900:4545:3:200:f8ff:fe21:67cf]' } + its(:hostname) { should == '3ffe:1900:4545:3:200:f8ff:fe21:67cf' } +end + +describe Addressable::URI, "when assigning IPv6 address" do + it "should allow to set bare IPv6 address as hostname" do + uri = Addressable::URI.parse("http://[::1]/") + uri.hostname = '3ffe:1900:4545:3:200:f8ff:fe21:67cf' + uri.to_s.should == 'http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/' + end + + it "should not allow to set bare IPv6 address as host" do + uri = Addressable::URI.parse("http://[::1]/") + pending "not checked" + (lambda do + uri.host = '3ffe:1900:4545:3:200:f8ff:fe21:67cf' + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsing IPvFuture addresses" do + it "should not raise an error for " + + "'http://[v9.3ffe:1900:4545:3:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[v9.3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[vff.fe80:0:0:0:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[vff.fe80:0:0:0:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[v12.fe80::200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[v12.fe80::200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[va0.::1]/'" do + Addressable::URI.parse("http://[va0.::1]/") + end + + it "should not raise an error for " + + "'http://[v255.fe80::1]/'" do + Addressable::URI.parse("http://[v255.fe80::1]/") + end + + it "should raise an error for " + + "'http://[v0.]/'" do + (lambda do + Addressable::URI.parse("http://[v0.]/") + end).should raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/'" do + before do + @uri = Addressable::URI.parse("http://example.com/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com" do + @uri.should == Addressable::URI.parse("http://example.com") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to HTTP://example.com/" do + @uri.should == Addressable::URI.parse("HTTP://example.com/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com:/" do + @uri.should == Addressable::URI.parse("http://example.com:/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com:80/" do + @uri.should == Addressable::URI.parse("http://example.com:80/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://Example.com/" do + @uri.should == Addressable::URI.parse("http://Example.com/") + end + + it "should have the correct username after assignment" do + @uri.user = nil + @uri.user.should == nil + @uri.password.should == nil + @uri.to_s.should == "http://example.com/" + end + + it "should have the correct password after assignment" do + @uri.password = nil + @uri.password.should == nil + @uri.user.should == nil + @uri.to_s.should == "http://example.com/" + end + + it "should have a request URI of '/'" do + @uri.request_uri.should == "/" + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have the same hash as its duplicate" do + @uri.hash.should == @uri.dup.hash + end + + it "should have a different hash from its equivalent String value" do + @uri.hash.should_not == @uri.to_s.hash + end + + it "should have the same hash as an equal URI" do + @uri.hash.should == Addressable::URI.parse("http://example.com/").hash + end + + it "should be equivalent to http://EXAMPLE.com" do + @uri.should == Addressable::URI.parse("http://EXAMPLE.com") + end + + it "should be equivalent to http://EXAMPLE.com:80/" do + @uri.should == Addressable::URI.parse("http://EXAMPLE.com:80/") + end + + it "should have the same hash as http://example.com/" do + @uri.hash.should == Addressable::URI.parse("http://example.com/").hash + end + + it "should have the same hash as http://example.com after assignment" do + @uri.path = "" + @uri.hash.should == Addressable::URI.parse("http://example.com").hash + end + + it "should have the same hash as http://example.com/? after assignment" do + @uri.query = "" + @uri.hash.should == Addressable::URI.parse("http://example.com/?").hash + end + + it "should have the same hash as http://example.com/? after assignment" do + @uri.query_values = {} + @uri.hash.should == Addressable::URI.parse("http://example.com/?").hash + end + + it "should have the same hash as http://example.com/# after assignment" do + @uri.fragment = "" + @uri.hash.should == Addressable::URI.parse("http://example.com/#").hash + end + + it "should have a different hash from http://example.com" do + @uri.hash.should_not == Addressable::URI.parse("http://example.com").hash + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com?#'" do + before do + @uri = Addressable::URI.parse("http://example.com?#") + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "", + :query => "", + :fragment => "" + } + end + + it "should have a request URI of '/?'" do + @uri.request_uri.should == "/?" + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == "http://example.com" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://@example.com/'" do + before do + @uri = Addressable::URI.parse("http://@example.com/") + end + + it "should be equivalent to http://example.com" do + @uri.should == Addressable::URI.parse("http://example.com") + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => "", + :password => nil, + :host => "example.com", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com./'" do + before do + @uri = Addressable::URI.parse("http://example.com./") + end + + it "should be equivalent to http://example.com" do + @uri.should == Addressable::URI.parse("http://example.com") + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://:@example.com/'" do + before do + @uri = Addressable::URI.parse("http://:@example.com/") + end + + it "should be equivalent to http://example.com" do + @uri.should == Addressable::URI.parse("http://example.com") + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => "", + :password => "", + :host => "example.com", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/~smith/'" do + before do + @uri = Addressable::URI.parse("http://example.com/~smith/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com/%7Esmith/" do + @uri.should == Addressable::URI.parse("http://example.com/%7Esmith/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com/%7esmith/" do + @uri.should == Addressable::URI.parse("http://example.com/%7esmith/") + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/%E8'" do + before do + @uri = Addressable::URI.parse("http://example.com/%E8") + end + + it "should not raise an exception when normalized" do + (lambda do + @uri.normalize + end).should_not raise_error + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should not change if encoded with the normalizing algorithm" do + Addressable::URI.normalized_encode(@uri).to_s.should == + "http://example.com/%E8" + Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should === + "http://example.com/%E8" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path%2Fsegment/'" do + before do + @uri = Addressable::URI.parse("http://example.com/path%2Fsegment/") + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should be equal to 'http://example.com/path%2Fsegment/'" do + @uri.normalize.should be_eql( + Addressable::URI.parse("http://example.com/path%2Fsegment/") + ) + end + + it "should not be equal to 'http://example.com/path/segment/'" do + @uri.should_not == + Addressable::URI.parse("http://example.com/path/segment/") + end + + it "should not be equal to 'http://example.com/path/segment/'" do + @uri.normalize.should_not be_eql( + Addressable::URI.parse("http://example.com/path/segment/") + ) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?%F6'" do + before do + @uri = Addressable::URI.parse("http://example.com/?%F6") + end + + it "should not raise an exception when normalized" do + (lambda do + @uri.normalize + end).should_not raise_error + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should not change if encoded with the normalizing algorithm" do + Addressable::URI.normalized_encode(@uri).to_s.should == + "http://example.com/?%F6" + Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should === + "http://example.com/?%F6" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/#%F6'" do + before do + @uri = Addressable::URI.parse("http://example.com/#%F6") + end + + it "should not raise an exception when normalized" do + (lambda do + @uri.normalize + end).should_not raise_error + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should not change if encoded with the normalizing algorithm" do + Addressable::URI.normalized_encode(@uri).to_s.should == + "http://example.com/#%F6" + Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should === + "http://example.com/#%F6" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/%C3%87'" do + before do + @uri = Addressable::URI.parse("http://example.com/%C3%87") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to 'http://example.com/C%CC%A7'" do + @uri.should == Addressable::URI.parse("http://example.com/C%CC%A7") + end + + it "should not change if encoded with the normalizing algorithm" do + Addressable::URI.normalized_encode(@uri).to_s.should == + "http://example.com/%C3%87" + Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should === + "http://example.com/%C3%87" + end + + it "should raise an error if encoding with an unexpected return type" do + (lambda do + Addressable::URI.normalized_encode(@uri, Integer) + end).should raise_error(TypeError) + end + + it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do + Addressable::URI.encode(@uri).to_s.should == + "http://example.com/%25C3%2587" + end + + it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do + Addressable::URI.encode(@uri, Addressable::URI).should == + Addressable::URI.parse("http://example.com/%25C3%2587") + end + + it "should raise an error if encoding with an unexpected return type" do + (lambda do + Addressable::URI.encode(@uri, Integer) + end).should raise_error(TypeError) + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=string'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=string") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com'" do + @uri.authority.should == "example.com" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/'" do + @uri.path.should == "/" + end + + it "should have a query string of 'q=string'" do + @uri.query.should == "q=string" + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should be considered absolute" do + @uri.should be_absolute + end + + it "should not be considered relative" do + @uri.should_not be_relative + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com:80/'" do + before do + @uri = Addressable::URI.parse("http://example.com:80/") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com:80'" do + @uri.authority.should == "example.com:80" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have explicit port 80" do + @uri.port.should == 80 + end + + it "should have a path of '/'" do + @uri.path.should == "/" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should be considered absolute" do + @uri.should be_absolute + end + + it "should not be considered relative" do + @uri.should_not be_relative + end + + it "should be exactly equal to http://example.com:80/" do + @uri.eql?(Addressable::URI.parse("http://example.com:80/")).should == true + end + + it "should be roughly equal to http://example.com/" do + (@uri === Addressable::URI.parse("http://example.com/")).should == true + end + + it "should be roughly equal to the string 'http://example.com/'" do + (@uri === "http://example.com/").should == true + end + + it "should not be roughly equal to the string " + + "'http://example.com:bogus/'" do + (lambda do + (@uri === "http://example.com:bogus/").should == false + end).should_not raise_error + end + + it "should result in itself when joined with itself" do + @uri.join(@uri).to_s.should == "http://example.com:80/" + @uri.join!(@uri).to_s.should == "http://example.com:80/" + end + + # Section 6.2.3 of RFC 3986 + it "should be equal to http://example.com/" do + @uri.should == Addressable::URI.parse("http://example.com/") + end + + # Section 6.2.3 of RFC 3986 + it "should be equal to http://example.com:/" do + @uri.should == Addressable::URI.parse("http://example.com:/") + end + + # Section 6.2.3 of RFC 3986 + it "should be equal to http://example.com:80/" do + @uri.should == Addressable::URI.parse("http://example.com:80/") + end + + # Section 6.2.2.1 of RFC 3986 + it "should be equal to http://EXAMPLE.COM/" do + @uri.should == Addressable::URI.parse("http://EXAMPLE.COM/") + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => 80, + :path => "/", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end + + it "should not change if encoded with the normalizing algorithm" do + Addressable::URI.normalized_encode(@uri).to_s.should == + "http://example.com:80/" + Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should === + "http://example.com:80/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com:8080/'" do + before do + @uri = Addressable::URI.parse("http://example.com:8080/") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com:8080'" do + @uri.authority.should == "example.com:8080" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 8080" do + @uri.inferred_port.should == 8080 + end + + it "should have explicit port 8080" do + @uri.port.should == 8080 + end + + it "should have default port 80" do + @uri.default_port.should == 80 + end + + it "should have a path of '/'" do + @uri.path.should == "/" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should be considered absolute" do + @uri.should be_absolute + end + + it "should not be considered relative" do + @uri.should_not be_relative + end + + it "should be exactly equal to http://example.com:8080/" do + @uri.eql?(Addressable::URI.parse( + "http://example.com:8080/")).should == true + end + + it "should have a route of 'http://example.com:8080/' from " + + "'http://example.com/path/to/'" do + @uri.route_from("http://example.com/path/to/").should == + Addressable::URI.parse("http://example.com:8080/") + end + + it "should have a route of 'http://example.com:8080/' from " + + "'http://example.com:80/path/to/'" do + @uri.route_from("http://example.com:80/path/to/").should == + Addressable::URI.parse("http://example.com:8080/") + end + + it "should have a route of '../../' from " + + "'http://example.com:8080/path/to/'" do + @uri.route_from("http://example.com:8080/path/to/").should == + Addressable::URI.parse("../../") + end + + it "should have a route of 'http://example.com:8080/' from " + + "'http://user:pass@example.com/path/to/'" do + @uri.route_from("http://user:pass@example.com/path/to/").should == + Addressable::URI.parse("http://example.com:8080/") + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => 8080, + :path => "/", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com:8080'" do + @uri.origin.should == 'http://example.com:8080' + end + + it "should not change if encoded with the normalizing algorithm" do + Addressable::URI.normalized_encode(@uri).to_s.should == + "http://example.com:8080/" + Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should === + "http://example.com:8080/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com:%38%30/'" do + before do + @uri = Addressable::URI.parse("http://example.com:%38%30/") + end + + it "should have the correct port" do + @uri.port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/%2E/'" do + before do + @uri = Addressable::URI.parse("http://example.com/%2E/") + end + + it "should be considered to be in normal form" do + pending( + 'path segment normalization should happen before ' + + 'percent escaping normalization' + ) do + @uri.normalize.should be_eql(@uri) + end + end + + it "should normalize to 'http://example.com/%2E/'" do + pending( + 'path segment normalization should happen before ' + + 'percent escaping normalization' + ) do + @uri.normalize.should == "http://example.com/%2E/" + end + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/..'" do + before do + @uri = Addressable::URI.parse("http://example.com/..") + end + + it "should have the correct port" do + @uri.inferred_port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/../..'" do + before do + @uri = Addressable::URI.parse("http://example.com/../..") + end + + it "should have the correct port" do + @uri.inferred_port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path(/..'" do + before do + @uri = Addressable::URI.parse("http://example.com/path(/..") + end + + it "should have the correct port" do + @uri.inferred_port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/(path)/..'" do + before do + @uri = Addressable::URI.parse("http://example.com/(path)/..") + end + + it "should have the correct port" do + @uri.inferred_port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path(/../'" do + before do + @uri = Addressable::URI.parse("http://example.com/path(/../") + end + + it "should have the correct port" do + @uri.inferred_port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/(path)/../'" do + before do + @uri = Addressable::URI.parse("http://example.com/(path)/../") + end + + it "should have the correct port" do + @uri.inferred_port.should == 80 + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when parsed from '/a/b/c/./../../g'" do + before do + @uri = Addressable::URI.parse("/a/b/c/./../../g") + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + # Section 5.2.4 of RFC 3986 + it "should normalize to '/a/g'" do + @uri.normalize.to_s.should == "/a/g" + end +end + +describe Addressable::URI, "when parsed from 'mid/content=5/../6'" do + before do + @uri = Addressable::URI.parse("mid/content=5/../6") + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + # Section 5.2.4 of RFC 3986 + it "should normalize to 'mid/6'" do + @uri.normalize.to_s.should == "mid/6" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.example.com///../'" do + before do + @uri = Addressable::URI.parse('http://www.example.com///../') + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end + + it "should normalize to 'http://www.example.com//'" do + @uri.normalize.to_s.should == "http://www.example.com//" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path/to/resource/'" do + before do + @uri = Addressable::URI.parse("http://example.com/path/to/resource/") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com'" do + @uri.authority.should == "example.com" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/path/to/resource/'" do + @uri.path.should == "/path/to/resource/" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should be considered absolute" do + @uri.should be_absolute + end + + it "should not be considered relative" do + @uri.should_not be_relative + end + + it "should be exactly equal to http://example.com:8080/" do + @uri.eql?(Addressable::URI.parse( + "http://example.com/path/to/resource/")).should == true + end + + it "should have a route of 'resource/' from " + + "'http://example.com/path/to/'" do + @uri.route_from("http://example.com/path/to/").should == + Addressable::URI.parse("resource/") + end + + it "should have a route of '../' from " + + "'http://example.com/path/to/resource/sub'" do + @uri.route_from("http://example.com/path/to/resource/sub").should == + Addressable::URI.parse("../") + end + + + it "should have a route of 'resource/' from " + + "'http://example.com/path/to/another'" do + @uri.route_from("http://example.com/path/to/another").should == + Addressable::URI.parse("resource/") + end + + it "should have a route of 'resource/' from " + + "'http://example.com/path/to/res'" do + @uri.route_from("http://example.com/path/to/res").should == + Addressable::URI.parse("resource/") + end + + it "should have a route of 'resource/' from " + + "'http://example.com:80/path/to/'" do + @uri.route_from("http://example.com:80/path/to/").should == + Addressable::URI.parse("resource/") + end + + it "should have a route of 'http://example.com/path/to/' from " + + "'http://example.com:8080/path/to/'" do + @uri.route_from("http://example.com:8080/path/to/").should == + Addressable::URI.parse("http://example.com/path/to/resource/") + end + + it "should have a route of 'http://example.com/path/to/' from " + + "'http://user:pass@example.com/path/to/'" do + @uri.route_from("http://user:pass@example.com/path/to/").should == + Addressable::URI.parse("http://example.com/path/to/resource/") + end + + it "should have a route of '../../path/to/resource/' from " + + "'http://example.com/to/resource/'" do + @uri.route_from("http://example.com/to/resource/").should == + Addressable::URI.parse("../../path/to/resource/") + end + + it "should correctly convert to a hash" do + @uri.to_hash.should == { + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "/path/to/resource/", + :query => nil, + :fragment => nil + } + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end +end + +describe Addressable::URI, "when parsed from " + + "'relative/path/to/resource'" do + before do + @uri = Addressable::URI.parse("relative/path/to/resource") + end + + it "should not have a scheme" do + @uri.scheme.should == nil + end + + it "should not be considered ip-based" do + @uri.should_not be_ip_based + end + + it "should not have an authority segment" do + @uri.authority.should == nil + end + + it "should not have a host" do + @uri.host.should == nil + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should not have a port" do + @uri.port.should == nil + end + + it "should have a path of 'relative/path/to/resource'" do + @uri.path.should == "relative/path/to/resource" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should not be considered absolute" do + @uri.should_not be_absolute + end + + it "should be considered relative" do + @uri.should be_relative + end + + it "should raise an error if routing is attempted" do + (lambda do + @uri.route_to("http://example.com/") + end).should raise_error(ArgumentError, /relative\/path\/to\/resource/) + (lambda do + @uri.route_from("http://example.com/") + end).should raise_error(ArgumentError, /relative\/path\/to\/resource/) + end + + it "when joined with 'another/relative/path' should be " + + "'relative/path/to/another/relative/path'" do + @uri.join('another/relative/path').should == + Addressable::URI.parse("relative/path/to/another/relative/path") + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end +end + +describe Addressable::URI, "when parsed from " + + "'relative_path_with_no_slashes'" do + before do + @uri = Addressable::URI.parse("relative_path_with_no_slashes") + end + + it "should not have a scheme" do + @uri.scheme.should == nil + end + + it "should not be considered ip-based" do + @uri.should_not be_ip_based + end + + it "should not have an authority segment" do + @uri.authority.should == nil + end + + it "should not have a host" do + @uri.host.should == nil + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should not have a port" do + @uri.port.should == nil + end + + it "should have a path of 'relative_path_with_no_slashes'" do + @uri.path.should == "relative_path_with_no_slashes" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should not be considered absolute" do + @uri.should_not be_absolute + end + + it "should be considered relative" do + @uri.should be_relative + end + + it "when joined with 'another_relative_path' should be " + + "'another_relative_path'" do + @uri.join('another_relative_path').should == + Addressable::URI.parse("another_relative_path") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/file.txt'" do + before do + @uri = Addressable::URI.parse("http://example.com/file.txt") + end + + it "should have a scheme of 'http'" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com'" do + @uri.authority.should == "example.com" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/file.txt'" do + @uri.path.should == "/file.txt" + end + + it "should have a basename of 'file.txt'" do + @uri.basename.should == "file.txt" + end + + it "should have an extname of '.txt'" do + @uri.extname.should == ".txt" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/file.txt;parameter'" do + before do + @uri = Addressable::URI.parse("http://example.com/file.txt;parameter") + end + + it "should have a scheme of 'http'" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com'" do + @uri.authority.should == "example.com" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/file.txt;parameter'" do + @uri.path.should == "/file.txt;parameter" + end + + it "should have a basename of 'file.txt'" do + @uri.basename.should == "file.txt" + end + + it "should have an extname of '.txt'" do + @uri.extname.should == ".txt" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/file.txt;x=y'" do + before do + @uri = Addressable::URI.parse("http://example.com/file.txt;x=y") + end + + it "should have a scheme of 'http'" do + @uri.scheme.should == "http" + end + + it "should have a scheme of 'http'" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'example.com'" do + @uri.authority.should == "example.com" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have no username" do + @uri.user.should == nil + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/file.txt;x=y'" do + @uri.path.should == "/file.txt;x=y" + end + + it "should have an extname of '.txt'" do + @uri.extname.should == ".txt" + end + + it "should have no query string" do + @uri.query.should == nil + end + + it "should have no fragment" do + @uri.fragment.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'svn+ssh://developername@rubyforge.org/var/svn/project'" do + before do + @uri = Addressable::URI.parse( + "svn+ssh://developername@rubyforge.org/var/svn/project" + ) + end + + it "should have a scheme of 'svn+ssh'" do + @uri.scheme.should == "svn+ssh" + end + + it "should be considered to be ip-based" do + @uri.should be_ip_based + end + + it "should have a path of '/var/svn/project'" do + @uri.path.should == "/var/svn/project" + end + + it "should have a username of 'developername'" do + @uri.user.should == "developername" + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'ssh+svn://developername@RUBYFORGE.ORG/var/svn/project'" do + before do + @uri = Addressable::URI.parse( + "ssh+svn://developername@RUBYFORGE.ORG/var/svn/project" + ) + end + + it "should have a scheme of 'ssh+svn'" do + @uri.scheme.should == "ssh+svn" + end + + it "should have a normalized scheme of 'svn+ssh'" do + @uri.normalized_scheme.should == "svn+ssh" + end + + it "should have a normalized site of 'svn+ssh'" do + @uri.normalized_site.should == "svn+ssh://developername@rubyforge.org" + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should have a path of '/var/svn/project'" do + @uri.path.should == "/var/svn/project" + end + + it "should have a username of 'developername'" do + @uri.user.should == "developername" + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should not be considered to be in normal form" do + @uri.normalize.should_not be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'mailto:user@example.com'" do + before do + @uri = Addressable::URI.parse("mailto:user@example.com") + end + + it "should have a scheme of 'mailto'" do + @uri.scheme.should == "mailto" + end + + it "should not be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should have a path of 'user@example.com'" do + @uri.path.should == "user@example.com" + end + + it "should have no user" do + @uri.user.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'tag:example.com,2006-08-18:/path/to/something'" do + before do + @uri = Addressable::URI.parse( + "tag:example.com,2006-08-18:/path/to/something") + end + + it "should have a scheme of 'tag'" do + @uri.scheme.should == "tag" + end + + it "should be considered to be ip-based" do + @uri.should_not be_ip_based + end + + it "should have a path of " + + "'example.com,2006-08-18:/path/to/something'" do + @uri.path.should == "example.com,2006-08-18:/path/to/something" + end + + it "should have no user" do + @uri.user.should == nil + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/x;y/'" do + before do + @uri = Addressable::URI.parse("http://example.com/x;y/") + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?x=1&y=2'" do + before do + @uri = Addressable::URI.parse("http://example.com/?x=1&y=2") + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'view-source:http://example.com/'" do + before do + @uri = Addressable::URI.parse("view-source:http://example.com/") + end + + it "should have a scheme of 'view-source'" do + @uri.scheme.should == "view-source" + end + + it "should have a path of 'http://example.com/'" do + @uri.path.should == "http://example.com/" + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://user:pass@example.com/path/to/resource?query=x#fragment'" do + before do + @uri = Addressable::URI.parse( + "http://user:pass@example.com/path/to/resource?query=x#fragment") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have an authority segment of 'user:pass@example.com'" do + @uri.authority.should == "user:pass@example.com" + end + + it "should have a username of 'user'" do + @uri.user.should == "user" + end + + it "should have a password of 'pass'" do + @uri.password.should == "pass" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/path/to/resource'" do + @uri.path.should == "/path/to/resource" + end + + it "should have a query string of 'query=x'" do + @uri.query.should == "query=x" + end + + it "should have a fragment of 'fragment'" do + @uri.fragment.should == "fragment" + end + + it "should be considered to be in normal form" do + @uri.normalize.should be_eql(@uri) + end + + it "should have a route of '../../' to " + + "'http://user:pass@example.com/path/'" do + @uri.route_to("http://user:pass@example.com/path/").should == + Addressable::URI.parse("../../") + end + + it "should have a route of 'to/resource?query=x#fragment' " + + "from 'http://user:pass@example.com/path/'" do + @uri.route_from("http://user:pass@example.com/path/").should == + Addressable::URI.parse("to/resource?query=x#fragment") + end + + it "should have a route of '?query=x#fragment' " + + "from 'http://user:pass@example.com/path/to/resource'" do + @uri.route_from("http://user:pass@example.com/path/to/resource").should == + Addressable::URI.parse("?query=x#fragment") + end + + it "should have a route of '#fragment' " + + "from 'http://user:pass@example.com/path/to/resource?query=x'" do + @uri.route_from( + "http://user:pass@example.com/path/to/resource?query=x").should == + Addressable::URI.parse("#fragment") + end + + it "should have a route of '#fragment' from " + + "'http://user:pass@example.com/path/to/resource?query=x#fragment'" do + @uri.route_from( + "http://user:pass@example.com/path/to/resource?query=x#fragment" + ).should == Addressable::URI.parse("#fragment") + end + + it "should have a route of 'http://elsewhere.com/' to " + + "'http://elsewhere.com/'" do + @uri.route_to("http://elsewhere.com/").should == + Addressable::URI.parse("http://elsewhere.com/") + end + + it "should have a route of " + + "'http://user:pass@example.com/path/to/resource?query=x#fragment' " + + "from 'http://example.com/path/to/'" do + @uri.route_from("http://elsewhere.com/path/to/").should == + Addressable::URI.parse( + "http://user:pass@example.com/path/to/resource?query=x#fragment") + end + + it "should have the correct scheme after assignment" do + @uri.scheme = "ftp" + @uri.scheme.should == "ftp" + @uri.to_s.should == + "ftp://user:pass@example.com/path/to/resource?query=x#fragment" + @uri.to_str.should == + "ftp://user:pass@example.com/path/to/resource?query=x#fragment" + @uri.scheme = "bogus!" + @uri.scheme.should == "bogus!" + @uri.normalized_scheme.should == "bogus%21" + @uri.normalize.to_s.should == + "bogus%21://user:pass@example.com/path/to/resource?query=x#fragment" + @uri.normalize.to_str.should == + "bogus%21://user:pass@example.com/path/to/resource?query=x#fragment" + end + + it "should have the correct site segment after assignment" do + @uri.site = "https://newuser:newpass@example.com:443" + @uri.scheme.should == "https" + @uri.authority.should == "newuser:newpass@example.com:443" + @uri.user.should == "newuser" + @uri.password.should == "newpass" + @uri.userinfo.should == "newuser:newpass" + @uri.normalized_userinfo.should == "newuser:newpass" + @uri.host.should == "example.com" + @uri.port.should == 443 + @uri.inferred_port.should == 443 + @uri.to_s.should == + "https://newuser:newpass@example.com:443" + + "/path/to/resource?query=x#fragment" + end + + it "should have the correct authority segment after assignment" do + @uri.authority = "newuser:newpass@example.com:80" + @uri.authority.should == "newuser:newpass@example.com:80" + @uri.user.should == "newuser" + @uri.password.should == "newpass" + @uri.userinfo.should == "newuser:newpass" + @uri.normalized_userinfo.should == "newuser:newpass" + @uri.host.should == "example.com" + @uri.port.should == 80 + @uri.inferred_port.should == 80 + @uri.to_s.should == + "http://newuser:newpass@example.com:80" + + "/path/to/resource?query=x#fragment" + end + + it "should have the correct userinfo segment after assignment" do + @uri.userinfo = "newuser:newpass" + @uri.userinfo.should == "newuser:newpass" + @uri.authority.should == "newuser:newpass@example.com" + @uri.user.should == "newuser" + @uri.password.should == "newpass" + @uri.host.should == "example.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == + "http://newuser:newpass@example.com" + + "/path/to/resource?query=x#fragment" + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.authority.should == "newuser:pass@example.com" + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.authority.should == "user:newpass@example.com" + end + + it "should have the correct host after assignment" do + @uri.host = "newexample.com" + @uri.host.should == "newexample.com" + @uri.authority.should == "user:pass@newexample.com" + end + + it "should have the correct port after assignment" do + @uri.port = 8080 + @uri.port.should == 8080 + @uri.authority.should == "user:pass@example.com:8080" + end + + it "should have the correct path after assignment" do + @uri.path = "/newpath/to/resource" + @uri.path.should == "/newpath/to/resource" + @uri.to_s.should == + "http://user:pass@example.com/newpath/to/resource?query=x#fragment" + end + + it "should have the correct scheme and authority after nil assignment" do + @uri.site = nil + @uri.scheme.should == nil + @uri.authority.should == nil + @uri.to_s.should == "/path/to/resource?query=x#fragment" + end + + it "should have the correct scheme and authority after assignment" do + @uri.site = "file://" + @uri.scheme.should == "file" + @uri.authority.should == "" + @uri.to_s.should == "file:///path/to/resource?query=x#fragment" + end + + it "should have the correct path after nil assignment" do + @uri.path = nil + @uri.path.should == "" + @uri.to_s.should == + "http://user:pass@example.com?query=x#fragment" + end + + it "should have the correct query string after assignment" do + @uri.query = "newquery=x" + @uri.query.should == "newquery=x" + @uri.to_s.should == + "http://user:pass@example.com/path/to/resource?newquery=x#fragment" + @uri.query = nil + @uri.query.should == nil + @uri.to_s.should == + "http://user:pass@example.com/path/to/resource#fragment" + end + + it "should have the correct query string after hash assignment" do + @uri.query_values = {"?uestion mark" => "=sign", "hello" => "g\xC3\xBCnther"} + @uri.query.split("&").should include("%3Fuestion%20mark=%3Dsign") + @uri.query.split("&").should include("hello=g%C3%BCnther") + @uri.query_values.should == { + "?uestion mark" => "=sign", "hello" => "g\xC3\xBCnther" + } + end + + it "should have the correct query string after flag hash assignment" do + @uri.query_values = {'flag?1' => nil, 'fl=ag2' => nil, 'flag3' => nil} + @uri.query.split("&").should include("flag%3F1") + @uri.query.split("&").should include("fl%3Dag2") + @uri.query.split("&").should include("flag3") + @uri.query_values(Array).sort.should == [["fl=ag2"], ["flag3"], ["flag?1"]] + @uri.query_values(Hash).should == { + 'flag?1' => nil, 'fl=ag2' => nil, 'flag3' => nil + } + end + + it "should raise an error if query values are set to a bogus type" do + (lambda do + @uri.query_values = "bogus" + end).should raise_error(TypeError) + end + + it "should have the correct fragment after assignment" do + @uri.fragment = "newfragment" + @uri.fragment.should == "newfragment" + @uri.to_s.should == + "http://user:pass@example.com/path/to/resource?query=x#newfragment" + + @uri.fragment = nil + @uri.fragment.should == nil + @uri.to_s.should == + "http://user:pass@example.com/path/to/resource?query=x" + end + + it "should have the correct values after a merge" do + @uri.merge(:fragment => "newfragment").to_s.should == + "http://user:pass@example.com/path/to/resource?query=x#newfragment" + end + + it "should have the correct values after a merge" do + @uri.merge(:fragment => nil).to_s.should == + "http://user:pass@example.com/path/to/resource?query=x" + end + + it "should have the correct values after a merge" do + @uri.merge(:userinfo => "newuser:newpass").to_s.should == + "http://newuser:newpass@example.com/path/to/resource?query=x#fragment" + end + + it "should have the correct values after a merge" do + @uri.merge(:userinfo => nil).to_s.should == + "http://example.com/path/to/resource?query=x#fragment" + end + + it "should have the correct values after a merge" do + @uri.merge(:path => "newpath").to_s.should == + "http://user:pass@example.com/newpath?query=x#fragment" + end + + it "should have the correct values after a merge" do + @uri.merge(:port => "42", :path => "newpath", :query => "").to_s.should == + "http://user:pass@example.com:42/newpath?#fragment" + end + + it "should have the correct values after a merge" do + @uri.merge(:authority => "foo:bar@baz:42").to_s.should == + "http://foo:bar@baz:42/path/to/resource?query=x#fragment" + # Ensure the operation was not destructive + @uri.to_s.should == + "http://user:pass@example.com/path/to/resource?query=x#fragment" + end + + it "should have the correct values after a destructive merge" do + @uri.merge!(:authority => "foo:bar@baz:42") + # Ensure the operation was destructive + @uri.to_s.should == + "http://foo:bar@baz:42/path/to/resource?query=x#fragment" + end + + it "should fail to merge with bogus values" do + (lambda do + @uri.merge(:port => "bogus") + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should fail to merge with bogus values" do + (lambda do + @uri.merge(:authority => "bar@baz:bogus") + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should fail to merge with bogus parameters" do + (lambda do + @uri.merge(42) + end).should raise_error(TypeError) + end + + it "should fail to merge with bogus parameters" do + (lambda do + @uri.merge("http://example.com/") + end).should raise_error(TypeError) + end + + it "should fail to merge with both authority and subcomponents" do + (lambda do + @uri.merge(:authority => "foo:bar@baz:42", :port => "42") + end).should raise_error(ArgumentError) + end + + it "should fail to merge with both userinfo and subcomponents" do + (lambda do + @uri.merge(:userinfo => "foo:bar", :user => "foo") + end).should raise_error(ArgumentError) + end + + it "should be identical to its duplicate" do + @uri.should == @uri.dup + end + + it "should have an origin of 'http://example.com'" do + @uri.origin.should == 'http://example.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/search?q=Q%26A'" do + + before do + @uri = Addressable::URI.parse("http://example.com/search?q=Q%26A") + end + + it "should have a query of 'q=Q%26A'" do + @uri.query.should == "q=Q%26A" + end + + it "should have query_values of {'q' => 'Q&A'}" do + @uri.query_values.should == { 'q' => 'Q&A' } + end + + it "should normalize to the original uri " + + "(with the ampersand properly percent-encoded)" do + @uri.normalize.to_s.should == "http://example.com/search?q=Q%26A" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?&x=b") + end + + it "should have a query of '&x=b'" do + @uri.query.should == "&x=b" + end + + it "should have query_values of {'x' => 'b'}" do + @uri.query_values.should == {'x' => 'b'} + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q='one;two'&x=1'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q='one;two'&x=1") + end + + it "should have a query of 'q='one;two'&x=1'" do + @uri.query.should == "q='one;two'&x=1" + end + + it "should have query_values of {\"q\" => \"'one;two'\", \"x\" => \"1\"}" do + @uri.query_values.should == {"q" => "'one;two'", "x" => "1"} + end + + it "should escape the ';' character when normalizing to avoid ambiguity " + + "with the W3C HTML 4.01 specification" do + # HTML 4.01 Section B.2.2 + @uri.normalize.query.should == "q='one%3Btwo'&x=1" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?&&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?&&x=b") + end + + it "should have a query of '&&x=b'" do + @uri.query.should == "&&x=b" + end + + it "should have query_values of {'x' => 'b'}" do + @uri.query_values.should == {'x' => 'b'} + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=a&&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=a&&x=b") + end + + it "should have a query of 'q=a&&x=b'" do + @uri.query.should == "q=a&&x=b" + end + + it "should have query_values of {'q' => 'a, 'x' => 'b'}" do + @uri.query_values.should == {'q' => 'a', 'x' => 'b'} + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q&&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q&&x=b") + end + + it "should have a query of 'q&&x=b'" do + @uri.query.should == "q&&x=b" + end + + it "should have query_values of {'q' => true, 'x' => 'b'}" do + @uri.query_values.should == {'q' => nil, 'x' => 'b'} + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=a+b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=a+b") + end + + it "should have a query of 'q=a+b'" do + @uri.query.should == "q=a+b" + end + + it "should have query_values of {'q' => 'a b'}" do + @uri.query_values.should == {'q' => 'a b'} + end + + it "should have a normalized query of 'q=a+b'" do + @uri.normalized_query.should == "q=a+b" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=a%2bb'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=a%2bb") + end + + it "should have a query of 'q=a+b'" do + @uri.query.should == "q=a%2bb" + end + + it "should have query_values of {'q' => 'a+b'}" do + @uri.query_values.should == {'q' => 'a+b'} + end + + it "should have a normalized query of 'q=a%2Bb'" do + @uri.normalized_query.should == "q=a%2Bb" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?v=%7E&w=%&x=%25&y=%2B&z=C%CC%A7'" do + before do + @uri = Addressable::URI.parse("http://example.com/?v=%7E&w=%&x=%25&y=%2B&z=C%CC%A7") + end + + it "should have a normalized query of 'v=~&w=%25&x=%25&y=%2B&z=%C3%87'" do + @uri.normalized_query.should == "v=~&w=%25&x=%25&y=%2B&z=%C3%87" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?v=%7E&w=%&x=%25&y=+&z=C%CC%A7'" do + before do + @uri = Addressable::URI.parse("http://example.com/?v=%7E&w=%&x=%25&y=+&z=C%CC%A7") + end + + it "should have a normalized query of 'v=~&w=%25&x=%25&y=+&z=%C3%87'" do + @uri.normalized_query.should == "v=~&w=%25&x=%25&y=+&z=%C3%87" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/sound%2bvision'" do + before do + @uri = Addressable::URI.parse("http://example.com/sound%2bvision") + end + + it "should have a normalized path of '/sound+vision'" do + @uri.normalized_path.should == '/sound+vision' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q='" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=") + end + + it "should have a query of 'q='" do + @uri.query.should == "q=" + end + + it "should have query_values of {'q' => ''}" do + @uri.query_values.should == {'q' => ''} + end +end + +describe Addressable::URI, "when parsed from " + + "'http://user@example.com'" do + before do + @uri = Addressable::URI.parse("http://user@example.com") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have a username of 'user'" do + @uri.user.should == "user" + end + + it "should have no password" do + @uri.password.should == nil + end + + it "should have a userinfo of 'user'" do + @uri.userinfo.should == "user" + end + + it "should have a normalized userinfo of 'user'" do + @uri.normalized_userinfo.should == "user" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have default_port 80" do + @uri.default_port.should == 80 + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password.should == nil + @uri.to_s.should == "http://newuser@example.com" + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.to_s.should == "http://user:newpass@example.com" + end + + it "should have the correct userinfo segment after assignment" do + @uri.userinfo = "newuser:newpass" + @uri.userinfo.should == "newuser:newpass" + @uri.user.should == "newuser" + @uri.password.should == "newpass" + @uri.host.should == "example.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == "http://newuser:newpass@example.com" + end + + it "should have the correct userinfo segment after nil assignment" do + @uri.userinfo = nil + @uri.userinfo.should == nil + @uri.user.should == nil + @uri.password.should == nil + @uri.host.should == "example.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == "http://example.com" + end + + it "should have the correct authority segment after assignment" do + @uri.authority = "newuser@example.com" + @uri.authority.should == "newuser@example.com" + @uri.user.should == "newuser" + @uri.password.should == nil + @uri.host.should == "example.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == "http://newuser@example.com" + end + + it "should raise an error after nil assignment of authority segment" do + (lambda do + # This would create an invalid URI + @uri.authority = nil + end).should raise_error + end +end + +describe Addressable::URI, "when parsed from " + + "'http://user:@example.com'" do + before do + @uri = Addressable::URI.parse("http://user:@example.com") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have a username of 'user'" do + @uri.user.should == "user" + end + + it "should have a password of ''" do + @uri.password.should == "" + end + + it "should have a normalized userinfo of 'user:'" do + @uri.normalized_userinfo.should == "user:" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password.should == "" + @uri.to_s.should == "http://newuser:@example.com" + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.to_s.should == "http://user:newpass@example.com" + end + + it "should have the correct authority segment after assignment" do + @uri.authority = "newuser:@example.com" + @uri.authority.should == "newuser:@example.com" + @uri.user.should == "newuser" + @uri.password.should == "" + @uri.host.should == "example.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == "http://newuser:@example.com" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://:pass@example.com'" do + before do + @uri = Addressable::URI.parse("http://:pass@example.com") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have a username of ''" do + @uri.user.should == "" + end + + it "should have a password of 'pass'" do + @uri.password.should == "pass" + end + + it "should have a userinfo of ':pass'" do + @uri.userinfo.should == ":pass" + end + + it "should have a normalized userinfo of ':pass'" do + @uri.normalized_userinfo.should == ":pass" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password.should == "pass" + @uri.to_s.should == "http://newuser:pass@example.com" + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.user.should == "" + @uri.to_s.should == "http://:newpass@example.com" + end + + it "should have the correct authority segment after assignment" do + @uri.authority = ":newpass@example.com" + @uri.authority.should == ":newpass@example.com" + @uri.user.should == "" + @uri.password.should == "newpass" + @uri.host.should == "example.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == "http://:newpass@example.com" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://:@example.com'" do + before do + @uri = Addressable::URI.parse("http://:@example.com") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have a username of ''" do + @uri.user.should == "" + end + + it "should have a password of ''" do + @uri.password.should == "" + end + + it "should have a normalized userinfo of nil" do + @uri.normalized_userinfo.should == nil + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + @uri.user.should == "newuser" + @uri.password.should == "" + @uri.to_s.should == "http://newuser:@example.com" + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + @uri.password.should == "newpass" + @uri.user.should == "" + @uri.to_s.should == "http://:newpass@example.com" + end + + it "should have the correct authority segment after assignment" do + @uri.authority = ":@newexample.com" + @uri.authority.should == ":@newexample.com" + @uri.user.should == "" + @uri.password.should == "" + @uri.host.should == "newexample.com" + @uri.port.should == nil + @uri.inferred_port.should == 80 + @uri.to_s.should == "http://:@newexample.com" + end +end + +describe Addressable::URI, "when parsed from " + + "'#example'" do + before do + @uri = Addressable::URI.parse("#example") + end + + it "should be considered relative" do + @uri.should be_relative + end + + it "should have a host of nil" do + @uri.host.should == nil + end + + it "should have a site of nil" do + @uri.site.should == nil + end + + it "should have a normalized_site of nil" do + @uri.normalized_site.should == nil + end + + it "should have a path of ''" do + @uri.path.should == "" + end + + it "should have a query string of nil" do + @uri.query.should == nil + end + + it "should have a fragment of 'example'" do + @uri.fragment.should == "example" + end +end + +describe Addressable::URI, "when parsed from " + + "the network-path reference '//example.com/'" do + before do + @uri = Addressable::URI.parse("//example.com/") + end + + it "should be considered relative" do + @uri.should be_relative + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should have a path of '/'" do + @uri.path.should == "/" + end + + it "should raise an error if routing is attempted" do + (lambda do + @uri.route_to("http://example.com/") + end).should raise_error(ArgumentError, /\/\/example.com\//) + (lambda do + @uri.route_from("http://example.com/") + end).should raise_error(ArgumentError, /\/\/example.com\//) + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from " + + "'feed://http://example.com/'" do + before do + @uri = Addressable::URI.parse("feed://http://example.com/") + end + + it "should have a host of 'http'" do + @uri.host.should == "http" + end + + it "should have a path of '//example.com/'" do + @uri.path.should == "//example.com/" + end +end + +describe Addressable::URI, "when parsed from " + + "'feed:http://example.com/'" do + before do + @uri = Addressable::URI.parse("feed:http://example.com/") + end + + it "should have a path of 'http://example.com/'" do + @uri.path.should == "http://example.com/" + end + + it "should normalize to 'http://example.com/'" do + @uri.normalize.to_s.should == "http://example.com/" + @uri.normalize!.to_s.should == "http://example.com/" + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from " + + "'example://a/b/c/%7Bfoo%7D'" do + before do + @uri = Addressable::URI.parse("example://a/b/c/%7Bfoo%7D") + end + + # Section 6.2.2 of RFC 3986 + it "should be equivalent to eXAMPLE://a/./b/../b/%63/%7bfoo%7d" do + @uri.should == + Addressable::URI.parse("eXAMPLE://a/./b/../b/%63/%7bfoo%7d") + end + + it "should have an origin of 'example://a'" do + @uri.origin.should == 'example://a' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/indirect/path/./to/../resource/'" do + before do + @uri = Addressable::URI.parse( + "http://example.com/indirect/path/./to/../resource/") + end + + it "should use the 'http' scheme" do + @uri.scheme.should == "http" + end + + it "should have a host of 'example.com'" do + @uri.host.should == "example.com" + end + + it "should use port 80" do + @uri.inferred_port.should == 80 + end + + it "should have a path of '/indirect/path/./to/../resource/'" do + @uri.path.should == "/indirect/path/./to/../resource/" + end + + # Section 6.2.2.3 of RFC 3986 + it "should have a normalized path of '/indirect/path/resource/'" do + @uri.normalize.path.should == "/indirect/path/resource/" + @uri.normalize!.path.should == "/indirect/path/resource/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://under_score.example.com/'" do + it "should not cause an error" do + (lambda do + Addressable::URI.parse("http://under_score.example.com/") + end).should_not raise_error + end +end + +describe Addressable::URI, "when parsed from " + + "'./this:that'" do + before do + @uri = Addressable::URI.parse("./this:that") + end + + it "should be considered relative" do + @uri.should be_relative + end + + it "should have no scheme" do + @uri.scheme.should == nil + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from " + + "'this:that'" do + before do + @uri = Addressable::URI.parse("this:that") + end + + it "should be considered absolute" do + @uri.should be_absolute + end + + it "should have a scheme of 'this'" do + @uri.scheme.should == "this" + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from '?'" do + before do + @uri = Addressable::URI.parse("?") + end + + it "should normalize to ''" do + @uri.normalize.to_s.should == "" + end + + it "should have the correct return type" do + @uri.query_values.should == {} + @uri.query_values(Hash).should == {} + @uri.query_values(Array).should == [] + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from '?one=1&two=2&three=3'" do + before do + @uri = Addressable::URI.parse("?one=1&two=2&three=3") + end + + it "should have the correct query values" do + @uri.query_values.should == {"one" => "1", "two" => "2", "three" => "3"} + end + + it "should raise an error for invalid return type values" do + (lambda do + @uri.query_values(Fixnum) + end).should raise_error(ArgumentError) + end + + it "should have the correct array query values" do + @uri.query_values(Array).should == [ + ["one", "1"], ["two", "2"], ["three", "3"] + ] + end + + it "should have a 'null' origin" do + @uri.origin.should == 'null' + end +end + +describe Addressable::URI, "when parsed from '?one=1=uno&two=2=dos'" do + before do + @uri = Addressable::URI.parse("?one=1=uno&two=2=dos") + end + + it "should have the correct query values" do + @uri.query_values.should == {"one" => "1=uno", "two" => "2=dos"} + end + + it "should have the correct array query values" do + @uri.query_values(Array).should == [ + ["one", "1=uno"], ["two", "2=dos"] + ] + end +end + +describe Addressable::URI, "when parsed from '?one[two][three]=four'" do + before do + @uri = Addressable::URI.parse("?one[two][three]=four") + end + + it "should have the correct query values" do + @uri.query_values.should == {"one[two][three]" => "four"} + end + + it "should have the correct array query values" do + @uri.query_values(Array).should == [ + ["one[two][three]", "four"] + ] + end +end + +describe Addressable::URI, "when parsed from '?one.two.three=four'" do + before do + @uri = Addressable::URI.parse("?one.two.three=four") + end + + it "should have the correct query values" do + @uri.query_values.should == { + "one.two.three" => "four" + } + end + + it "should have the correct array query values" do + @uri.query_values(Array).should == [ + ["one.two.three", "four"] + ] + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three]=four&one[two][five]=six'" do + before do + @uri = Addressable::URI.parse("?one[two][three]=four&one[two][five]=six") + end + + it "should have the correct query values" do + @uri.query_values.should == { + "one[two][three]" => "four", "one[two][five]" => "six" + } + end + + it "should have the correct array query values" do + @uri.query_values(Array).should == [ + ["one[two][three]", "four"], ["one[two][five]", "six"] + ] + end +end + +describe Addressable::URI, "when parsed from " + + "'?one.two.three=four&one.two.five=six'" do + before do + @uri = Addressable::URI.parse("?one.two.three=four&one.two.five=six") + end + + it "should have the correct query values" do + @uri.query_values.should == { + "one.two.three" => "four", "one.two.five" => "six" + } + end + + it "should have the correct array query values" do + @uri.query_values(Array).should == [ + ["one.two.three", "four"], ["one.two.five", "six"] + ] + end +end + +describe Addressable::URI, "when parsed from " + + "'?one=two&one=three'" do + before do + @uri = Addressable::URI.parse( + "?one=two&one=three&one=four" + ) + end + + it "should have correct array query values" do + @uri.query_values(Array).should == + [['one', 'two'], ['one', 'three'], ['one', 'four']] + end + + it "should have correct hash query values" do + pending("This is probably more desirable behavior.") do + @uri.query_values(Hash).should == + {'one' => ['two', 'three', 'four']} + end + end + + it "should handle assignment with keys of mixed type" do + @uri.query_values = @uri.query_values(Hash).merge({:one => 'three'}) + @uri.query_values(Hash).should == {'one' => 'three'} + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][]=four&one[two][three][]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][]=four&one[two][three][]=five" + ) + end + + it "should have correct query values" do + @uri.query_values(Hash).should == {"one[two][three][]" => "five"} + end + + it "should have correct array query values" do + @uri.query_values(Array).should == [ + ["one[two][three][]", "four"], ["one[two][three][]", "five"] + ] + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][0]=four&one[two][three][1]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][0]=four&one[two][three][1]=five" + ) + end + + it "should have the correct query values" do + @uri.query_values.should == { + "one[two][three][0]" => "four", "one[two][three][1]" => "five" + } + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][1]=four&one[two][three][0]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][1]=four&one[two][three][0]=five" + ) + end + + it "should have the correct query values" do + @uri.query_values.should == { + "one[two][three][1]" => "four", "one[two][three][0]" => "five" + } + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][2]=four&one[two][three][1]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][2]=four&one[two][three][1]=five" + ) + end + + it "should have the correct query values" do + @uri.query_values.should == { + "one[two][three][2]" => "four", "one[two][three][1]" => "five" + } + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.詹姆斯.com/'" do + before do + @uri = Addressable::URI.parse("http://www.詹姆斯.com/") + end + + it "should be equivalent to 'http://www.xn--8ws00zhy3a.com/'" do + @uri.should == + Addressable::URI.parse("http://www.xn--8ws00zhy3a.com/") + end + + it "should not have domain name encoded during normalization" do + Addressable::URI.normalized_encode(@uri.to_s).should == + "http://www.詹姆斯.com/" + end + + it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do + @uri.origin.should == 'http://www.xn--8ws00zhy3a.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.詹姆斯.com/ some spaces /'" do + before do + @uri = Addressable::URI.parse("http://www.詹姆斯.com/ some spaces /") + end + + it "should be equivalent to " + + "'http://www.xn--8ws00zhy3a.com/%20some%20spaces%20/'" do + @uri.should == + Addressable::URI.parse( + "http://www.xn--8ws00zhy3a.com/%20some%20spaces%20/") + end + + it "should not have domain name encoded during normalization" do + Addressable::URI.normalized_encode(@uri.to_s).should == + "http://www.詹姆斯.com/%20some%20spaces%20/" + end + + it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do + @uri.origin.should == 'http://www.xn--8ws00zhy3a.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.xn--8ws00zhy3a.com/'" do + before do + @uri = Addressable::URI.parse("http://www.xn--8ws00zhy3a.com/") + end + + it "should be displayed as http://www.詹姆斯.com/" do + @uri.display_uri.to_s.should == "http://www.詹姆斯.com/" + end + + it "should properly force the encoding" do + display_string = @uri.display_uri.to_str + display_string.should == "http://www.詹姆斯.com/" + if display_string.respond_to?(:encoding) + display_string.encoding.to_s.should == Encoding::UTF_8.to_s + end + end + + it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do + @uri.origin.should == 'http://www.xn--8ws00zhy3a.com' + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.詹姆斯.com/atomtests/iri/詹.html'" do + before do + @uri = Addressable::URI.parse("http://www.詹姆斯.com/atomtests/iri/詹.html") + end + + it "should normalize to " + + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" do + @uri.normalize.to_s.should == + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" + @uri.normalize!.to_s.should == + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" + end +end + +describe Addressable::URI, "when parsed from a percent-encoded IRI" do + before do + @uri = Addressable::URI.parse( + "http://www.%E3%81%BB%E3%82%93%E3%81%A8%E3%81%86%E3%81%AB%E3%81%AA" + + "%E3%81%8C%E3%81%84%E3%82%8F%E3%81%91%E3%81%AE%E3%82%8F%E3%81%8B%E3" + + "%82%89%E3%81%AA%E3%81%84%E3%81%A9%E3%82%81%E3%81%84%E3%82%93%E3%82" + + "%81%E3%81%84%E3%81%AE%E3%82%89%E3%81%B9%E3%82%8B%E3%81%BE%E3%81%A0" + + "%E3%81%AA%E3%81%8C%E3%81%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3" + + "%81%9F%E3%82%8A%E3%81%AA%E3%81%84.w3.mag.keio.ac.jp" + ) + end + + it "should normalize to something sane" do + @uri.normalize.to_s.should == + "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp/" + @uri.normalize!.to_s.should == + "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp/" + end + + it "should have the correct origin" do + @uri.origin.should == ( + "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + ) + end +end + +describe Addressable::URI, "with a base uri of 'http://a/b/c/d;p?q'" do + before do + @uri = Addressable::URI.parse("http://a/b/c/d;p?q") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g:h' should resolve to g:h" do + (@uri + "g:h").to_s.should == "g:h" + Addressable::URI.join(@uri, "g:h").to_s.should == "g:h" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g' should resolve to http://a/b/c/g" do + (@uri + "g").to_s.should == "http://a/b/c/g" + Addressable::URI.join(@uri.to_s, "g").to_s.should == "http://a/b/c/g" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with './g' should resolve to http://a/b/c/g" do + (@uri + "./g").to_s.should == "http://a/b/c/g" + Addressable::URI.join(@uri.to_s, "./g").to_s.should == "http://a/b/c/g" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g/' should resolve to http://a/b/c/g/" do + (@uri + "g/").to_s.should == "http://a/b/c/g/" + Addressable::URI.join(@uri.to_s, "g/").to_s.should == "http://a/b/c/g/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '/g' should resolve to http://a/g" do + (@uri + "/g").to_s.should == "http://a/g" + Addressable::URI.join(@uri.to_s, "/g").to_s.should == "http://a/g" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '//g' should resolve to http://g" do + (@uri + "//g").to_s.should == "http://g" + Addressable::URI.join(@uri.to_s, "//g").to_s.should == "http://g" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '?y' should resolve to http://a/b/c/d;p?y" do + (@uri + "?y").to_s.should == "http://a/b/c/d;p?y" + Addressable::URI.join(@uri.to_s, "?y").to_s.should == "http://a/b/c/d;p?y" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g?y' should resolve to http://a/b/c/g?y" do + (@uri + "g?y").to_s.should == "http://a/b/c/g?y" + Addressable::URI.join(@uri.to_s, "g?y").to_s.should == "http://a/b/c/g?y" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '#s' should resolve to http://a/b/c/d;p?q#s" do + (@uri + "#s").to_s.should == "http://a/b/c/d;p?q#s" + Addressable::URI.join(@uri.to_s, "#s").to_s.should == + "http://a/b/c/d;p?q#s" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g#s' should resolve to http://a/b/c/g#s" do + (@uri + "g#s").to_s.should == "http://a/b/c/g#s" + Addressable::URI.join(@uri.to_s, "g#s").to_s.should == "http://a/b/c/g#s" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g?y#s' should resolve to http://a/b/c/g?y#s" do + (@uri + "g?y#s").to_s.should == "http://a/b/c/g?y#s" + Addressable::URI.join( + @uri.to_s, "g?y#s").to_s.should == "http://a/b/c/g?y#s" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with ';x' should resolve to http://a/b/c/;x" do + (@uri + ";x").to_s.should == "http://a/b/c/;x" + Addressable::URI.join(@uri.to_s, ";x").to_s.should == "http://a/b/c/;x" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g;x' should resolve to http://a/b/c/g;x" do + (@uri + "g;x").to_s.should == "http://a/b/c/g;x" + Addressable::URI.join(@uri.to_s, "g;x").to_s.should == "http://a/b/c/g;x" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g;x?y#s' should resolve to http://a/b/c/g;x?y#s" do + (@uri + "g;x?y#s").to_s.should == "http://a/b/c/g;x?y#s" + Addressable::URI.join( + @uri.to_s, "g;x?y#s").to_s.should == "http://a/b/c/g;x?y#s" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '' should resolve to http://a/b/c/d;p?q" do + (@uri + "").to_s.should == "http://a/b/c/d;p?q" + Addressable::URI.join(@uri.to_s, "").to_s.should == "http://a/b/c/d;p?q" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '.' should resolve to http://a/b/c/" do + (@uri + ".").to_s.should == "http://a/b/c/" + Addressable::URI.join(@uri.to_s, ".").to_s.should == "http://a/b/c/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with './' should resolve to http://a/b/c/" do + (@uri + "./").to_s.should == "http://a/b/c/" + Addressable::URI.join(@uri.to_s, "./").to_s.should == "http://a/b/c/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '..' should resolve to http://a/b/" do + (@uri + "..").to_s.should == "http://a/b/" + Addressable::URI.join(@uri.to_s, "..").to_s.should == "http://a/b/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../' should resolve to http://a/b/" do + (@uri + "../").to_s.should == "http://a/b/" + Addressable::URI.join(@uri.to_s, "../").to_s.should == "http://a/b/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../g' should resolve to http://a/b/g" do + (@uri + "../g").to_s.should == "http://a/b/g" + Addressable::URI.join(@uri.to_s, "../g").to_s.should == "http://a/b/g" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../..' should resolve to http://a/" do + (@uri + "../..").to_s.should == "http://a/" + Addressable::URI.join(@uri.to_s, "../..").to_s.should == "http://a/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../../' should resolve to http://a/" do + (@uri + "../../").to_s.should == "http://a/" + Addressable::URI.join(@uri.to_s, "../../").to_s.should == "http://a/" + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../../g' should resolve to http://a/g" do + (@uri + "../../g").to_s.should == "http://a/g" + Addressable::URI.join(@uri.to_s, "../../g").to_s.should == "http://a/g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '../../../g' should resolve to http://a/g" do + (@uri + "../../../g").to_s.should == "http://a/g" + Addressable::URI.join(@uri.to_s, "../../../g").to_s.should == "http://a/g" + end + + it "when joined with '../.././../g' should resolve to http://a/g" do + (@uri + "../.././../g").to_s.should == "http://a/g" + Addressable::URI.join(@uri.to_s, "../.././../g").to_s.should == + "http://a/g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '../../../../g' should resolve to http://a/g" do + (@uri + "../../../../g").to_s.should == "http://a/g" + Addressable::URI.join( + @uri.to_s, "../../../../g").to_s.should == "http://a/g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '/./g' should resolve to http://a/g" do + (@uri + "/./g").to_s.should == "http://a/g" + Addressable::URI.join(@uri.to_s, "/./g").to_s.should == "http://a/g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '/../g' should resolve to http://a/g" do + (@uri + "/../g").to_s.should == "http://a/g" + Addressable::URI.join(@uri.to_s, "/../g").to_s.should == "http://a/g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g.' should resolve to http://a/b/c/g." do + (@uri + "g.").to_s.should == "http://a/b/c/g." + Addressable::URI.join(@uri.to_s, "g.").to_s.should == "http://a/b/c/g." + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '.g' should resolve to http://a/b/c/.g" do + (@uri + ".g").to_s.should == "http://a/b/c/.g" + Addressable::URI.join(@uri.to_s, ".g").to_s.should == "http://a/b/c/.g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g..' should resolve to http://a/b/c/g.." do + (@uri + "g..").to_s.should == "http://a/b/c/g.." + Addressable::URI.join(@uri.to_s, "g..").to_s.should == "http://a/b/c/g.." + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '..g' should resolve to http://a/b/c/..g" do + (@uri + "..g").to_s.should == "http://a/b/c/..g" + Addressable::URI.join(@uri.to_s, "..g").to_s.should == "http://a/b/c/..g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with './../g' should resolve to http://a/b/g" do + (@uri + "./../g").to_s.should == "http://a/b/g" + Addressable::URI.join(@uri.to_s, "./../g").to_s.should == "http://a/b/g" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with './g/.' should resolve to http://a/b/c/g/" do + (@uri + "./g/.").to_s.should == "http://a/b/c/g/" + Addressable::URI.join(@uri.to_s, "./g/.").to_s.should == "http://a/b/c/g/" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g/./h' should resolve to http://a/b/c/g/h" do + (@uri + "g/./h").to_s.should == "http://a/b/c/g/h" + Addressable::URI.join(@uri.to_s, "g/./h").to_s.should == "http://a/b/c/g/h" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g/../h' should resolve to http://a/b/c/h" do + (@uri + "g/../h").to_s.should == "http://a/b/c/h" + Addressable::URI.join(@uri.to_s, "g/../h").to_s.should == "http://a/b/c/h" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g;x=1/./y' " + + "should resolve to http://a/b/c/g;x=1/y" do + (@uri + "g;x=1/./y").to_s.should == "http://a/b/c/g;x=1/y" + Addressable::URI.join( + @uri.to_s, "g;x=1/./y").to_s.should == "http://a/b/c/g;x=1/y" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g;x=1/../y' should resolve to http://a/b/c/y" do + (@uri + "g;x=1/../y").to_s.should == "http://a/b/c/y" + Addressable::URI.join( + @uri.to_s, "g;x=1/../y").to_s.should == "http://a/b/c/y" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g?y/./x' " + + "should resolve to http://a/b/c/g?y/./x" do + (@uri + "g?y/./x").to_s.should == "http://a/b/c/g?y/./x" + Addressable::URI.join( + @uri.to_s, "g?y/./x").to_s.should == "http://a/b/c/g?y/./x" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g?y/../x' " + + "should resolve to http://a/b/c/g?y/../x" do + (@uri + "g?y/../x").to_s.should == "http://a/b/c/g?y/../x" + Addressable::URI.join( + @uri.to_s, "g?y/../x").to_s.should == "http://a/b/c/g?y/../x" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g#s/./x' " + + "should resolve to http://a/b/c/g#s/./x" do + (@uri + "g#s/./x").to_s.should == "http://a/b/c/g#s/./x" + Addressable::URI.join( + @uri.to_s, "g#s/./x").to_s.should == "http://a/b/c/g#s/./x" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g#s/../x' " + + "should resolve to http://a/b/c/g#s/../x" do + (@uri + "g#s/../x").to_s.should == "http://a/b/c/g#s/../x" + Addressable::URI.join( + @uri.to_s, "g#s/../x").to_s.should == "http://a/b/c/g#s/../x" + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'http:g' should resolve to http:g" do + (@uri + "http:g").to_s.should == "http:g" + Addressable::URI.join(@uri.to_s, "http:g").to_s.should == "http:g" + end + + # Edge case to be sure + it "when joined with '//example.com/' should " + + "resolve to http://example.com/" do + (@uri + "//example.com/").to_s.should == "http://example.com/" + Addressable::URI.join( + @uri.to_s, "//example.com/").to_s.should == "http://example.com/" + end + + it "when joined with a bogus object a TypeError should be raised" do + (lambda do + Addressable::URI.join(@uri, 42) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when converting the path " + + "'relative/path/to/something'" do + before do + @path = 'relative/path/to/something' + end + + it "should convert to " + + "\'relative/path/to/something\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "relative/path/to/something" + end + + it "should join with an absolute file path correctly" do + @base = Addressable::URI.convert_path("/absolute/path/") + @uri = Addressable::URI.convert_path(@path) + (@base + @uri).to_str.should == + "file:///absolute/path/relative/path/to/something" + end +end + +describe Addressable::URI, "when converting a bogus path" do + it "should raise a TypeError" do + (lambda do + Addressable::URI.convert_path(42) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when given a UNIX root directory" do + before do + @path = "/" + end + + it "should convert to \'file:///\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given a Windows root directory" do + before do + @path = "C:\\" + end + + it "should convert to \'file:///c:/\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///c:/" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given the path '/one/two/'" do + before do + @path = '/one/two/' + end + + it "should convert to " + + "\'file:///one/two/\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///one/two/" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given the path " + + "'c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///c:/windows/My%20Documents%20100%20/foo.txt" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given the path " + + "'file://c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "file://c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///c:/windows/My%20Documents%20100%20/foo.txt" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given the path " + + "'file:c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "file:c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///c:/windows/My%20Documents%20100%20/foo.txt" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given the path " + + "'file:/c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "file:/c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///c:/windows/My%20Documents%20100%20/foo.txt" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given the path " + + "'file:///c|/windows/My%20Documents%20100%20/foo.txt'" do + before do + @path = "file:///c|/windows/My%20Documents%20100%20/foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "file:///c:/windows/My%20Documents%20100%20/foo.txt" + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + @uri.origin.should == 'file://' + end +end + +describe Addressable::URI, "when given an http protocol URI" do + before do + @path = "http://example.com/" + end + + it "should not do any conversion at all" do + @uri = Addressable::URI.convert_path(@path) + @uri.to_str.should == "http://example.com/" + end +end + +class SuperString + def initialize(string) + @string = string.to_s + end + + def to_str + return @string + end +end + +describe Addressable::URI, "when parsing a non-String object" do + it "should correctly parse anything with a 'to_str' method" do + Addressable::URI.parse(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + (lambda do + Addressable::URI.parse(42) + end).should raise_error(TypeError, "Can't convert Fixnum into String.") + end + + it "should correctly parse heuristically anything with a 'to_str' method" do + Addressable::URI.heuristic_parse(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + (lambda do + Addressable::URI.heuristic_parse(42) + end).should raise_error(TypeError, "Can't convert Fixnum into String.") + end +end + +describe Addressable::URI, "when form encoding a hash" do + it "should result in correct percent encoded sequence" do + Addressable::URI.form_encode( + [["&one", "/1"], ["=two", "?2"], [":three", "#3"]] + ).should == "%26one=%2F1&%3Dtwo=%3F2&%3Athree=%233" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.form_encode( + {"q" => "one two three"} + ).should == "q=one+two+three" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.form_encode( + {"key" => nil} + ).should == "key=" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.form_encode( + {"q" => ["one", "two", "three"]} + ).should == "q=one&q=two&q=three" + end + + it "should result in correctly encoded newlines" do + Addressable::URI.form_encode( + {"text" => "one\ntwo\rthree\r\nfour\n\r"} + ).should == "text=one%0D%0Atwo%0D%0Athree%0D%0Afour%0D%0A%0D%0A" + end + + it "should result in a sorted percent encoded sequence" do + Addressable::URI.form_encode( + [["a", "1"], ["dup", "3"], ["dup", "2"]], true + ).should == "a=1&dup=2&dup=3" + end +end + +describe Addressable::URI, "when form encoding a non-Array object" do + it "should raise a TypeError for objects than cannot be converted" do + (lambda do + Addressable::URI.form_encode(42) + end).should raise_error(TypeError, "Can't convert Fixnum into Array.") + end +end + +describe Addressable::URI, "when form unencoding a string" do + it "should result in correct values" do + Addressable::URI.form_unencode( + "%26one=%2F1&%3Dtwo=%3F2&%3Athree=%233" + ).should == [["&one", "/1"], ["=two", "?2"], [":three", "#3"]] + end + + it "should result in correct values" do + Addressable::URI.form_unencode( + "q=one+two+three" + ).should == [["q", "one two three"]] + end + + it "should result in correct values" do + Addressable::URI.form_unencode( + "text=one%0D%0Atwo%0D%0Athree%0D%0Afour%0D%0A%0D%0A" + ).should == [["text", "one\ntwo\nthree\nfour\n\n"]] + end + + it "should result in correct values" do + Addressable::URI.form_unencode( + "a=1&dup=2&dup=3" + ).should == [["a", "1"], ["dup", "2"], ["dup", "3"]] + end + + it "should result in correct values" do + Addressable::URI.form_unencode( + "key" + ).should == [["key", nil]] + end + + it "should result in correct values" do + Addressable::URI.form_unencode("GivenName=Ren%C3%A9").should == + [["GivenName", "René"]] + end +end + +describe Addressable::URI, "when form unencoding a non-String object" do + it "should correctly parse anything with a 'to_str' method" do + Addressable::URI.form_unencode(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + (lambda do + Addressable::URI.form_unencode(42) + end).should raise_error(TypeError, "Can't convert Fixnum into String.") + end +end + +describe Addressable::URI, "when normalizing a non-String object" do + it "should correctly parse anything with a 'to_str' method" do + Addressable::URI.normalize_component(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + (lambda do + Addressable::URI.normalize_component(42) + end).should raise_error(TypeError, "Can't convert Fixnum into String.") + end + + it "should raise a TypeError for objects than cannot be converted" do + (lambda do + Addressable::URI.normalize_component("component", 42) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when normalizing a path with an encoded slash" do + it "should result in correct percent encoded sequence" do + Addressable::URI.parse("/path%2Fsegment/").normalize.path.should == + "/path%2Fsegment/" + end +end + +describe Addressable::URI, "when normalizing a partially encoded string" do + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component( + "partially % encoded%21" + ).should == "partially%20%25%20encoded!" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component( + "partially %25 encoded!" + ).should == "partially%20%25%20encoded!" + end +end + +describe Addressable::URI, "when normalizing a unicode sequence" do + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component( + "/C%CC%A7" + ).should == "/%C3%87" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component( + "/%C3%87" + ).should == "/%C3%87" + end +end + +describe Addressable::URI, "when normalizing a multibyte string" do + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component("günther").should == + "g%C3%BCnther" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component("g%C3%BCnther").should == + "g%C3%BCnther" + end +end + +describe Addressable::URI, "when normalizing a string but leaving some characters encoded" do + it "should result in correct percent encoded sequence" do + Addressable::URI.normalize_component("%58X%59Y%5AZ", "0-9a-zXY", "Y").should == + "XX%59Y%5A%5A" + end + + it "should not modify the character class" do + character_class = "0-9a-zXY" + + character_class_copy = character_class.dup + + Addressable::URI.normalize_component("%58X%59Y%5AZ", character_class, "Y") + + character_class.should == character_class_copy + end +end + +describe Addressable::URI, "when encoding a string with existing encodings to upcase" do + it "should result in correct percent encoded sequence" do + Addressable::URI.encode_component("JK%4c", "0-9A-IKM-Za-z%", "L").should == "%4AK%4C" + end +end + +describe Addressable::URI, "when encoding a multibyte string" do + it "should result in correct percent encoded sequence" do + Addressable::URI.encode_component("günther").should == "g%C3%BCnther" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.encode_component( + "günther", /[^a-zA-Z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\-\.\_\~]/ + ).should == "g%C3%BCnther" + end +end + +describe Addressable::URI, "when form encoding a multibyte string" do + it "should result in correct percent encoded sequence" do + Addressable::URI.form_encode({"GivenName" => "René"}).should == + "GivenName=Ren%C3%A9" + end +end + +describe Addressable::URI, "when encoding a string with ASCII chars 0-15" do + it "should result in correct percent encoded sequence" do + Addressable::URI.encode_component("one\ntwo").should == "one%0Atwo" + end + + it "should result in correct percent encoded sequence" do + Addressable::URI.encode_component( + "one\ntwo", /[^a-zA-Z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\-\.\_\~]/ + ).should == "one%0Atwo" + end +end + +describe Addressable::URI, "when unencoding a multibyte string" do + it "should result in correct percent encoded sequence" do + Addressable::URI.unencode_component("g%C3%BCnther").should == "günther" + end + + it "should consistently use UTF-8 internally" do + Addressable::URI.unencode_component("ski=%BA%DAɫ").should == "ski=\xBA\xDAɫ" + end + + it "should result in correct percent encoded sequence as a URI" do + Addressable::URI.unencode( + "/path?g%C3%BCnther", ::Addressable::URI + ).should == Addressable::URI.new( + :path => "/path", :query => "günther" + ) + end +end + +describe Addressable::URI, "when partially unencoding a string" do + it "should unencode all characters by default" do + Addressable::URI.unencode('%%25~%7e+%2b', String).should == '%%~~++' + end + + it "should unencode characters not in leave_encoded" do + Addressable::URI.unencode('%%25~%7e+%2b', String, '~').should == '%%~%7e++' + end + + it "should leave characters in leave_encoded alone" do + Addressable::URI.unencode('%%25~%7e+%2b', String, '%~+').should == '%%25~%7e+%2b' + end +end + +describe Addressable::URI, "when unencoding a bogus object" do + it "should raise a TypeError" do + (lambda do + Addressable::URI.unencode_component(42) + end).should raise_error(TypeError) + end + + it "should raise a TypeError" do + (lambda do + Addressable::URI.unencode("/path?g%C3%BCnther", Integer) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when encoding a bogus object" do + it "should raise a TypeError" do + (lambda do + Addressable::URI.encode(Object.new) + end).should raise_error(TypeError) + end + + it "should raise a TypeError" do + (lambda do + Addressable::URI.normalized_encode(Object.new) + end).should raise_error(TypeError) + end + + it "should raise a TypeError" do + (lambda do + Addressable::URI.encode_component("günther", Object.new) + end).should raise_error(TypeError) + end + + it "should raise a TypeError" do + (lambda do + Addressable::URI.encode_component(Object.new) + end).should raise_error(TypeError) + end +end + +describe Addressable::URI, "when given the input " + + "'http://example.com/'" do + before do + @input = "http://example.com/" + end + + it "should heuristically parse to 'http://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com/" + end + + it "should not raise error when frozen" do + (lambda do + Addressable::URI.heuristic_parse(@input).freeze.to_s + end).should_not raise_error + end +end + +describe Addressable::URI, "when given the input " + + "'https://example.com/'" do + before do + @input = "https://example.com/" + end + + it "should heuristically parse to 'https://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "https://example.com/" + end +end + +describe Addressable::URI, "when given the input " + + "'http:example.com/'" do + before do + @input = "http:example.com/" + end + + it "should heuristically parse to 'http://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com/" + end + + it "should heuristically parse to 'http://example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + @uri.to_s.should == "http://example.com/" + end +end + +describe Addressable::URI, "when given the input " + + "'https:example.com/'" do + before do + @input = "https:example.com/" + end + + it "should heuristically parse to 'https://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "https://example.com/" + end + + it "should heuristically parse to 'https://example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + @uri.to_s.should == "https://example.com/" + end +end + +describe Addressable::URI, "when given the input " + + "'http://example.com/example.com/'" do + before do + @input = "http://example.com/example.com/" + end + + it "should heuristically parse to 'http://example.com/example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com/example.com/" + end +end + +describe Addressable::URI, "when given the input " + + "'/path/to/resource'" do + before do + @input = "/path/to/resource" + end + + it "should heuristically parse to '/path/to/resource'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "/path/to/resource" + end +end + +describe Addressable::URI, "when given the input " + + "'relative/path/to/resource'" do + before do + @input = "relative/path/to/resource" + end + + it "should heuristically parse to 'relative/path/to/resource'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "relative/path/to/resource" + end +end + +describe Addressable::URI, "when given the input " + + "'example.com'" do + before do + @input = "example.com" + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com" + end +end + +describe Addressable::URI, "when given the input " + + "'example.com' and a scheme hint of 'ftp'" do + before do + @input = "example.com" + @hints = {:scheme => 'ftp'} + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input, @hints) + @uri.to_s.should == "ftp://example.com" + end +end + +describe Addressable::URI, "when given the input " + + "'example.com:21' and a scheme hint of 'ftp'" do + before do + @input = "example.com:21" + @hints = {:scheme => 'ftp'} + end + + it "should heuristically parse to 'http://example.com:21'" do + @uri = Addressable::URI.heuristic_parse(@input, @hints) + @uri.to_s.should == "ftp://example.com:21" + end +end + +describe Addressable::URI, "when given the input " + + "'example.com/path/to/resource'" do + before do + @input = "example.com/path/to/resource" + end + + it "should heuristically parse to 'http://example.com/path/to/resource'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com/path/to/resource" + end +end + +describe Addressable::URI, "when given the input " + + "'http:///example.com'" do + before do + @input = "http:///example.com" + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com" + end +end + +describe Addressable::URI, "when given the input " + + "'feed:///example.com'" do + before do + @input = "feed:///example.com" + end + + it "should heuristically parse to 'feed://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "feed://example.com" + end +end + +describe Addressable::URI, "when given the input " + + "'file://path/to/resource/'" do + before do + @input = "file://path/to/resource/" + end + + it "should heuristically parse to 'file:///path/to/resource/'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "file:///path/to/resource/" + end +end + +describe Addressable::URI, "when given the input " + + "'feed://http://example.com'" do + before do + @input = "feed://http://example.com" + end + + it "should heuristically parse to 'feed:http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "feed:http://example.com" + end +end + +describe Addressable::URI, "when given the input " + + "::URI.parse('http://example.com')" do + before do + @input = ::URI.parse('http://example.com') + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + @uri.to_s.should == "http://example.com" + end +end + +describe Addressable::URI, "when assigning query values" do + before do + @uri = Addressable::URI.new + end + + it "should correctly assign {:a => 'a', :b => ['c', 'd', 'e']}" do + @uri.query_values = {:a => "a", :b => ["c", "d", "e"]} + @uri.query.should == "a=a&b=c&b=d&b=e" + end + + it "should raise an error attempting to assign {'a' => {'b' => ['c']}}" do + (lambda do + @uri.query_values = { 'a' => {'b' => ['c'] } } + end).should raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:b => '2', :a => {:c => '1'}}" do + (lambda do + @uri.query_values = {:b => '2', :a => {:c => '1'}} + end).should raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => [{:c => 'c', :d => 'd'}, " + + "{:e => 'e', :f => 'f'}]}" do + (lambda do + @uri.query_values = { + :a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}] + } + end).should raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => [{:c => true, :d => 'd'}, " + + "{:e => 'e', :f => 'f'}]}" do + (lambda do + @uri.query_values = { + :a => 'a', :b => [{:c => true, :d => 'd'}, {:e => 'e', :f => 'f'}] + } + end).should raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => {:c => true, :d => 'd'}}" do + (lambda do + @uri.query_values = { + :a => 'a', :b => {:c => true, :d => 'd'} + } + end).should raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => {:c => true, :d => 'd'}}" do + (lambda do + @uri.query_values = { + :a => 'a', :b => {:c => true, :d => 'd'} + } + end).should raise_error(TypeError) + end + + it "should correctly assign {:a => 1, :b => 1.5}" do + @uri.query_values = { :a => 1, :b => 1.5 } + @uri.query.should == "a=1&b=1.5" + end + + it "should raise an error attempting to assign " + + "{:z => 1, :f => [2, {999.1 => [3,'4']}, ['h', 'i']], " + + ":a => {:b => ['c', 'd'], :e => true, :y => 0.5}}" do + (lambda do + @uri.query_values = { + :z => 1, + :f => [ 2, {999.1 => [3,'4']}, ['h', 'i'] ], + :a => { :b => ['c', 'd'], :e => true, :y => 0.5 } + } + end).should raise_error(TypeError) + end + + it "should correctly assign {}" do + @uri.query_values = {} + @uri.query.should == '' + end + + it "should correctly assign nil" do + @uri.query_values = nil + @uri.query.should == nil + end + + it "should correctly sort {'ab' => 'c', :ab => 'a', :a => 'x'}" do + @uri.query_values = {'ab' => 'c', :ab => 'a', :a => 'x'} + @uri.query.should == "a=x&ab=a&ab=c" + end + + it "should correctly assign " + + "[['b', 'c'], ['b', 'a'], ['a', 'a']]" do + # Order can be guaranteed in this format, so preserve it. + @uri.query_values = [['b', 'c'], ['b', 'a'], ['a', 'a']] + @uri.query.should == "b=c&b=a&a=a" + end + + it "should preserve query string order" do + query_string = (('a'..'z').to_a.reverse.map { |e| "#{e}=#{e}" }).join("&") + @uri.query = query_string + original_uri = @uri.to_s + @uri.query_values = @uri.query_values(Array) + @uri.to_s.should == original_uri + end + + describe 'when a hash with mixed types is assigned to query_values' do + it 'should not raise an error' do + pending 'Issue #94' do + expect { subject.query_values = { "page" => "1", :page => 2 } }.to_not raise_error + end + end + end +end + +describe Addressable::URI, "when assigning path values" do + before do + @uri = Addressable::URI.new + end + + it "should correctly assign paths containing colons" do + @uri.path = "acct:bob@sporkmonger.com" + @uri.path.should == "acct:bob@sporkmonger.com" + @uri.normalize.to_str.should == "acct%2Fbob@sporkmonger.com" + (lambda { @uri.to_s }).should raise_error( + Addressable::URI::InvalidURIError + ) + end + + it "should correctly assign paths containing colons" do + @uri.path = "/acct:bob@sporkmonger.com" + @uri.authority = "example.com" + @uri.normalize.to_str.should == "//example.com/acct:bob@sporkmonger.com" + end + + it "should correctly assign paths containing colons" do + @uri.path = "acct:bob@sporkmonger.com" + @uri.scheme = "something" + @uri.normalize.to_str.should == "something:acct:bob@sporkmonger.com" + end + + it "should not allow relative paths to be assigned on absolute URIs" do + (lambda do + @uri.scheme = "http" + @uri.host = "example.com" + @uri.path = "acct:bob@sporkmonger.com" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should not allow relative paths to be assigned on absolute URIs" do + (lambda do + @uri.path = "acct:bob@sporkmonger.com" + @uri.scheme = "http" + @uri.host = "example.com" + end).should raise_error(Addressable::URI::InvalidURIError) + end + + it "should not allow relative paths to be assigned on absolute URIs" do + (lambda do + @uri.path = "uuid:0b3ecf60-3f93-11df-a9c3-001f5bfffe12" + @uri.scheme = "urn" + end).should_not raise_error + end +end + +describe Addressable::URI, "when initializing a subclass of Addressable::URI" do + before do + @uri = Class.new(Addressable::URI).new + end + + it "should have the same class after being parsed" do + @uri.class.should == Addressable::URI.parse(@uri).class + end + + it "should have the same class as its duplicate" do + @uri.class.should == @uri.dup.class + end + + it "should have the same class after being normalized" do + @uri.class.should == @uri.normalize.class + end + + it "should have the same class after being merged" do + @uri.class.should == @uri.merge(:path => 'path').class + end + + it "should have the same class after being joined" do + @uri.class.should == @uri.join('path').class + end +end diff --git a/.gems/gems/addressable-2.3.6/spec/spec_helper.rb b/.gems/gems/addressable-2.3.6/spec/spec_helper.rb new file mode 100644 index 0000000..e0020ba --- /dev/null +++ b/.gems/gems/addressable-2.3.6/spec/spec_helper.rb @@ -0,0 +1,6 @@ +begin + require 'coveralls' + Coveralls.wear! +rescue LoadError + warn "warning: coveralls gem not found; skipping Coveralls" +end diff --git a/.gems/gems/addressable-2.3.6/tasks/clobber.rake b/.gems/gems/addressable-2.3.6/tasks/clobber.rake new file mode 100644 index 0000000..093ce81 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/clobber.rake @@ -0,0 +1,2 @@ +desc "Remove all build products" +task "clobber" diff --git a/.gems/gems/addressable-2.3.6/tasks/gem.rake b/.gems/gems/addressable-2.3.6/tasks/gem.rake new file mode 100644 index 0000000..8596712 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/gem.rake @@ -0,0 +1,86 @@ +require "rubygems/package_task" + +namespace :gem do + GEM_SPEC = Gem::Specification.new do |s| + s.name = PKG_NAME + s.version = PKG_VERSION + s.summary = PKG_SUMMARY + s.description = PKG_DESCRIPTION + + s.files = PKG_FILES.to_a + + s.has_rdoc = true + s.extra_rdoc_files = %w( README.md ) + s.rdoc_options.concat ["--main", "README.md"] + + if !s.respond_to?(:add_development_dependency) + puts "Cannot build Gem with this version of RubyGems." + exit(1) + end + + s.add_development_dependency("rake", ">= 0.7.3") + s.add_development_dependency("rspec", ">= 2.9.0") + s.add_development_dependency("launchy", ">= 0.3.2") + + s.require_path = "lib" + + s.author = "Bob Aman" + s.email = "bob@sporkmonger.com" + s.homepage = RUBY_FORGE_URL + s.rubyforge_project = RUBY_FORGE_PROJECT + s.license = "Apache License 2.0" + end + + Gem::PackageTask.new(GEM_SPEC) do |p| + p.gem_spec = GEM_SPEC + p.need_tar = true + p.need_zip = true + end + + desc "Generates .gemspec file" + task :gemspec do + spec_string = GEM_SPEC.to_ruby + + begin + Thread.new { eval("$SAFE = 3\n#{spec_string}", binding) }.join + rescue + abort "unsafe gemspec: #{$!}" + else + File.open("#{GEM_SPEC.name}.gemspec", 'w') do |file| + file.write spec_string + end + end + end + + desc "Show information about the gem" + task :debug do + puts GEM_SPEC.to_ruby + end + + desc "Install the gem" + task :install => ["clobber", "gem:package"] do + sh "#{SUDO} gem install --local pkg/#{GEM_SPEC.full_name}" + end + + desc "Uninstall the gem" + task :uninstall do + installed_list = Gem.source_index.find_name(PKG_NAME) + if installed_list && + (installed_list.collect { |s| s.version.to_s}.include?(PKG_VERSION)) + sh( + "#{SUDO} gem uninstall --version '#{PKG_VERSION}' " + + "--ignore-dependencies --executables #{PKG_NAME}" + ) + end + end + + desc "Reinstall the gem" + task :reinstall => [:uninstall, :install] +end + +desc "Alias to gem:package" +task "gem" => "gem:package" + +task "gem:release" => "gem:gemspec" + +task "clobber" => ["gem:clobber_package"] diff --git a/.gems/gems/addressable-2.3.6/tasks/git.rake b/.gems/gems/addressable-2.3.6/tasks/git.rake new file mode 100644 index 0000000..092032b --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/git.rake @@ -0,0 +1,45 @@ +namespace :git do + namespace :tag do + desc "List tags from the Git repository" + task :list do + tags = `git tag -l` + tags.gsub!("\r", "") + tags = tags.split("\n").sort {|a, b| b <=> a } + puts tags.join("\n") + end + + desc "Create a new tag in the Git repository" + task :create do + changelog = File.open("CHANGELOG.md", "r") { |file| file.read } + puts "-" * 80 + puts changelog + puts "-" * 80 + puts + + v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z" + abort "Versions don't match #{v} vs #{PKG_VERSION}" if v != PKG_VERSION + + git_status = `git status` + if git_status !~ /nothing to commit \(working directory clean\)/ + abort "Working directory isn't clean." + end + + tag = "#{PKG_NAME}-#{PKG_VERSION}" + msg = "Release #{PKG_NAME}-#{PKG_VERSION}" + + existing_tags = `git tag -l #{PKG_NAME}-*`.split('\n') + if existing_tags.include?(tag) + warn("Tag already exists, deleting...") + unless system "git tag -d #{tag}" + abort "Tag deletion failed." + end + end + puts "Creating git tag '#{tag}'..." + unless system "git tag -a -m \"#{msg}\" #{tag}" + abort "Tag creation failed." + end + end + end +end + +task "gem:release" => "git:tag:create" diff --git a/.gems/gems/addressable-2.3.6/tasks/metrics.rake b/.gems/gems/addressable-2.3.6/tasks/metrics.rake new file mode 100644 index 0000000..41fc5c2 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/metrics.rake @@ -0,0 +1,22 @@ +namespace :metrics do + task :lines do + lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 + for file_name in FileList["lib/**/*.rb"] + f = File.open(file_name) + while line = f.gets + lines += 1 + next if line =~ /^\s*$/ + next if line =~ /^\s*#/ + codelines += 1 + end + puts "L: #{sprintf("%4d", lines)}, " + + "LOC #{sprintf("%4d", codelines)} | #{file_name}" + total_lines += lines + total_codelines += codelines + + lines, codelines = 0, 0 + end + + puts "Total: Lines #{total_lines}, LOC #{total_codelines}" + end +end diff --git a/.gems/gems/addressable-2.3.6/tasks/rspec.rake b/.gems/gems/addressable-2.3.6/tasks/rspec.rake new file mode 100644 index 0000000..6b7e3a7 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/rspec.rake @@ -0,0 +1,58 @@ +require "rspec/core/rake_task" + +namespace :spec do + RSpec::Core::RakeTask.new(:rcov) do |t| + t.pattern = FileList['spec/**/*_spec.rb'] + t.rspec_opts = ['--color', '--format', 'documentation'] + + t.rcov = RCOV_ENABLED + t.rcov_opts = [ + '--exclude', 'lib\\/compat', + '--exclude', 'spec', + '--exclude', '\\.rvm\\/gems', + '--exclude', '1\\.8\\/gems', + '--exclude', '1\\.9\\/gems', + '--exclude', '\\.rvm', + '--exclude', '\\/Library\\/Ruby', + '--exclude', 'addressable\\/idna' # environment dependant + ] + end + + RSpec::Core::RakeTask.new(:normal) do |t| + t.pattern = FileList['spec/**/*_spec.rb'].exclude(/compat/) + t.rspec_opts = ['--color', '--format', 'documentation'] + t.rcov = false + end + + RSpec::Core::RakeTask.new(:all) do |t| + t.pattern = FileList['spec/**/*_spec.rb'] + t.rspec_opts = ['--color', '--format', 'documentation'] + t.rcov = false + end + + desc "Generate HTML Specdocs for all specs" + RSpec::Core::RakeTask.new(:specdoc) do |t| + specdoc_path = File.expand_path( + File.join(File.dirname(__FILE__), '..', 'documentation') + ) + Dir.mkdir(specdoc_path) if !File.exist?(specdoc_path) + + output_file = File.join(specdoc_path, 'index.html') + t.pattern = FileList['spec/**/*_spec.rb'] + t.rspec_opts = ["--format", "\"html:#{output_file}\"", "--diff"] + t.fail_on_error = false + end + + namespace :rcov do + desc "Browse the code coverage report." + task :browse => "spec:rcov" do + require "launchy" + Launchy::Browser.run("coverage/index.html") + end + end +end + +desc "Alias to spec:normal" +task "spec" => "spec:normal" + +task "clobber" => ["spec:clobber_rcov"] diff --git a/.gems/gems/addressable-2.3.6/tasks/rubyforge.rake b/.gems/gems/addressable-2.3.6/tasks/rubyforge.rake new file mode 100644 index 0000000..61d2ddb --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/rubyforge.rake @@ -0,0 +1,73 @@ +namespace :gem do + desc 'Package and upload to RubyForge' + task :release => ["gem:package", "gem:gemspec"] do |t| + require 'rubyforge' + + v = ENV['VERSION'] or abort 'Must supply VERSION=x.y.z' + abort "Versions don't match #{v} vs #{PROJ.version}" if v != PKG_VERSION + pkg = "pkg/#{GEM_SPEC.full_name}" + + rf = RubyForge.new + rf.configure + puts 'Logging in...' + rf.login + + c = rf.userconfig + changelog = File.open("CHANGELOG.md") { |file| file.read } + c['release_changes'] = changelog + c['preformatted'] = true + + files = ["#{pkg}.tgz", "#{pkg}.zip", "#{pkg}.gem"] + + puts "Releasing #{PKG_NAME} v. #{PKG_VERSION}" + rf.add_release RUBY_FORGE_PROJECT, PKG_NAME, PKG_VERSION, *files + end +end + +namespace :spec do + desc "Publish specdoc to RubyForge" + task :release => ["spec:specdoc"] do + require "rake/contrib/sshpublisher" + require "yaml" + + config = YAML.load( + File.read(File.expand_path('~/.rubyforge/user-config.yml')) + ) + host = "#{config['username']}@rubyforge.org" + remote_dir = RUBY_FORGE_PATH + "/specdoc" + local_dir = "specdoc" + Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload + end + + namespace :rcov do + desc "Publish coverage report to RubyForge" + task :release => ["spec:rcov"] do + require "rake/contrib/sshpublisher" + require "yaml" + + config = YAML.load( + File.read(File.expand_path('~/.rubyforge/user-config.yml')) + ) + host = "#{config['username']}@rubyforge.org" + remote_dir = RUBY_FORGE_PATH + "/coverage" + local_dir = "coverage" + Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload + end + end +end + +namespace :website do + desc "Publish website to RubyForge" + task :release => ["doc:release", "spec:release", "spec:rcov:release"] do + require "rake/contrib/sshpublisher" + require "yaml" + + config = YAML.load( + File.read(File.expand_path('~/.rubyforge/user-config.yml')) + ) + host = "#{config['username']}@rubyforge.org" + remote_dir = RUBY_FORGE_PATH + local_dir = "website" + Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload + end +end diff --git a/.gems/gems/addressable-2.3.6/tasks/yard.rake b/.gems/gems/addressable-2.3.6/tasks/yard.rake new file mode 100644 index 0000000..68e4491 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/tasks/yard.rake @@ -0,0 +1,27 @@ +require "rake" + +begin + require "yard" + require "yard/rake/yardoc_task" + + namespace :doc do + desc "Generate Yardoc documentation" + YARD::Rake::YardocTask.new do |yardoc| + yardoc.name = "yard" + yardoc.options = ["--verbose", "--markup", "markdown"] + yardoc.files = FileList[ + "lib/**/*.rb", "ext/**/*.c", + "README.md", "CHANGELOG.md", "LICENSE.txt" + ].exclude(/idna/) + end + end + + task "clobber" => ["doc:clobber_yard"] + + desc "Alias to doc:yard" + task "doc" => "doc:yard" +rescue LoadError + # If yard isn't available, it's not the end of the world + desc "Alias to doc:rdoc" + task "doc" => "doc:rdoc" +end diff --git a/.gems/gems/addressable-2.3.6/website/index.html b/.gems/gems/addressable-2.3.6/website/index.html new file mode 100644 index 0000000..ba92bd6 --- /dev/null +++ b/.gems/gems/addressable-2.3.6/website/index.html @@ -0,0 +1,110 @@ + + + + + Addressable + + + +

    Addressable

    +
    +

    + Addressable is a replacement for the URI implementation that is part + of Ruby's standard library. It more closely conforms to the relevant + RFCs and adds support for IRIs and URI templates. +

    + +

    + You know what to do: +

    +

    + sudo gem install addressable +

    +

    + Alternatively, you can: +

    +

    + + git submodule add + git://github.com/sporkmonger/addressable.git + vendor/gems/addressable + +

    +

    + Addressable works in Ruby 1.8.x, 1.9.x, and JRuby. +

    +
    + + diff --git a/.gems/gems/buftok-0.2.0/CONTRIBUTING.md b/.gems/gems/buftok-0.2.0/CONTRIBUTING.md new file mode 100644 index 0000000..06c35bb --- /dev/null +++ b/.gems/gems/buftok-0.2.0/CONTRIBUTING.md @@ -0,0 +1,49 @@ +## Contributing +In the spirit of [free software][free-sw], **everyone** is encouraged to help +improve this project. Here are some ways *you* can contribute: + +[free-sw]: http://www.fsf.org/licensing/essays/free-sw.html + +* Use alpha, beta, and pre-release versions. +* Report bugs. +* Suggest new features. +* Write or edit documentation. +* Write specifications. +* Write code (**no patch is too small**: fix typos, add comments, clean up + inconsistent whitespace). +* Refactor code. +* Fix [issues][]. +* Review patches. + +[issues]: https://github.com/sferik/buftok/issues + +## Submitting an Issue +We use the [GitHub issue tracker][issues] to track bugs and features. Before +submitting a bug report or feature request, check to make sure it hasn't +already been submitted. When submitting a bug report, please include a [Gist][] +that includes a stack trace and any details that may be necessary to reproduce +the bug, including your gem version, Ruby version, and operating system. +Ideally, a bug report should include a pull request with failing specs. + +[gist]: https://gist.github.com/ + +## Submitting a Pull Request +1. [Fork the repository.][fork] +2. [Create a topic branch.][branch] +3. Add specs for your unimplemented feature or bug fix. +4. Run `bundle exec rake spec`. If your specs pass, return to step 3. +5. Implement your feature or bug fix. +6. Run `bundle exec rake spec`. If your specs fail, return to step 5. +7. Run `open coverage/index.html`. If your changes are not completely covered + by your tests, return to step 3. +8. Run `RUBYOPT=W2 bundle exec rake spec 2>&1 | grep buftok`. If your changes + produce any warnings, return to step 5. +9. Add documentation for your feature or bug fix. +10. Run `bundle exec rake yard`. If your changes are not 100% documented, go + back to step 9. +11. Commit and push your changes. +12. [Submit a pull request.][pr] + +[fork]: http://help.github.com/fork-a-repo/ +[branch]: http://learn.github.com/p/branching.html +[pr]: http://help.github.com/send-pull-requests/ diff --git a/.gems/gems/buftok-0.2.0/Gemfile b/.gems/gems/buftok-0.2.0/Gemfile new file mode 100644 index 0000000..976088b --- /dev/null +++ b/.gems/gems/buftok-0.2.0/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gem 'rake' +gem 'rdoc' + +gemspec diff --git a/.gems/gems/buftok-0.2.0/LICENSE.md b/.gems/gems/buftok-0.2.0/LICENSE.md new file mode 100644 index 0000000..426810a --- /dev/null +++ b/.gems/gems/buftok-0.2.0/LICENSE.md @@ -0,0 +1,56 @@ +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. diff --git a/.gems/gems/buftok-0.2.0/README.md b/.gems/gems/buftok-0.2.0/README.md new file mode 100644 index 0000000..afba76b --- /dev/null +++ b/.gems/gems/buftok-0.2.0/README.md @@ -0,0 +1,48 @@ +# BufferedTokenizer + +[![Gem Version](https://badge.fury.io/rb/buftok.png)][gem] +[![Build Status](https://travis-ci.org/sferik/buftok.png?branch=master)][travis] +[![Dependency Status](https://gemnasium.com/sferik/buftok.png?travis)][gemnasium] +[![Code Climate](https://codeclimate.com/github/sferik/buftok.png)][codeclimate] + +[gem]: https://rubygems.org/gems/buftok +[travis]: https://travis-ci.org/sferik/buftok +[gemnasium]: https://gemnasium.com/sferik/buftok +[codeclimate]: https://codeclimate.com/github/sferik/buftok + +###### Statefully split input data by a specifiable token + +BufferedTokenizer takes a delimiter upon instantiation, or acts line-based by +default. It allows input to be spoon-fed from some outside source which +receives arbitrary length datagrams which may-or-may-not contain the token by +which entities are delimited. In this respect it's ideally paired with +something like [EventMachine][]. + +[EventMachine]: http://rubyeventmachine.com/ + +## Supported Ruby Versions +This library aims to support and is [tested against][travis] the following Ruby +implementations: + +* Ruby 1.8.7 +* Ruby 1.9.2 +* Ruby 1.9.3 +* Ruby 2.0.0 + +If something doesn't work on one of these interpreters, it's a bug. + +This library may inadvertently work (or seem to work) on other Ruby +implementations, however support will only be provided for the versions listed +above. + +If you would like this library to support another Ruby version, you may +volunteer to be a maintainer. Being a maintainer entails making sure all tests +run and pass on that implementation. When something breaks on your +implementation, you will be responsible for providing patches in a timely +fashion. If critical issues for a particular implementation exist at the time +of a major release, support for that Ruby version may be dropped. + +## Copyright +Copyright (c) 2006-2013 Tony Arcieri, Martin Emde, Erik Michaels-Ober. +Distributed under the [Ruby license][license]. +[license]: http://www.ruby-lang.org/en/LICENSE.txt diff --git a/.gems/gems/buftok-0.2.0/Rakefile b/.gems/gems/buftok-0.2.0/Rakefile new file mode 100644 index 0000000..b2ba2d0 --- /dev/null +++ b/.gems/gems/buftok-0.2.0/Rakefile @@ -0,0 +1,66 @@ +require 'bundler' +require 'rdoc/task' +require 'rake/testtask' + +task :default => :test + +Bundler::GemHelper.install_tasks + +RDoc::Task.new do |task| + task.rdoc_dir = 'doc' + task.title = 'BufferedTokenizer' + task.rdoc_files.include('lib/**/*.rb') +end + +Rake::TestTask.new :test do |t| + t.libs << 'lib' + t.test_files = FileList['test/**/*.rb'] +end + +desc "Benchmark the current implementation" +task :bench do + require 'benchmark' + require File.expand_path('lib/buftok', File.dirname(__FILE__)) + + n = 50000 + delimiter = "\n\n" + + frequency1 = 1000 + puts "generating #{n} strings, with #{delimiter.inspect} every #{frequency1} strings..." + data1 = (0...n).map do |i| + (((i % frequency1 == 1) ? "\n" : "") + + ("s" * i) + + ((i % frequency1 == 0) ? "\n" : "")).freeze + end + + frequency2 = 10 + puts "generating #{n} strings, with #{delimiter.inspect} every #{frequency2} strings..." + data2 = (0...n).map do |i| + (((i % frequency2 == 1) ? "\n" : "") + + ("s" * i) + + ((i % frequency2 == 0) ? "\n" : "")).freeze + end + + Benchmark.bmbm do |x| + x.report("1 char, freq: #{frequency1}") do + bt1 = BufferedTokenizer.new + n.times { |i| bt1.extract(data1[i]) } + end + + x.report("2 char, freq: #{frequency1}") do + bt2 = BufferedTokenizer.new(delimiter) + n.times { |i| bt2.extract(data1[i]) } + end + + x.report("1 char, freq: #{frequency2}") do + bt3 = BufferedTokenizer.new + n.times { |i| bt3.extract(data2[i]) } + end + + x.report("2 char, freq: #{frequency2}") do + bt4 = BufferedTokenizer.new(delimiter) + n.times { |i| bt4.extract(data2[i]) } + end + + end +end diff --git a/.gems/gems/buftok-0.2.0/buftok.gemspec b/.gems/gems/buftok-0.2.0/buftok.gemspec new file mode 100644 index 0000000..e108dd3 --- /dev/null +++ b/.gems/gems/buftok-0.2.0/buftok.gemspec @@ -0,0 +1,17 @@ +Gem::Specification.new do |spec| + spec.add_development_dependency 'bundler', '~> 1.0' + spec.authors = ["Tony Arcieri", "Martin Emde", "Erik Michaels-Ober"] + spec.description = %q{BufferedTokenizer extracts token delimited entities from a sequence of arbitrary inputs} + spec.email = "sferik@gmail.com" + spec.files = %w(CONTRIBUTING.md Gemfile LICENSE.md README.md Rakefile buftok.gemspec) + spec.files += Dir.glob("lib/**/*.rb") + spec.files += Dir.glob("test/**/*.rb") + spec.test_files = spec.files.grep(%r{^test/}) + spec.homepage = "https://github.com/sferik/buftok" + spec.licenses = ['MIT'] + spec.name = "buftok" + spec.require_paths = ["lib"] + spec.required_rubygems_version = '>= 1.3.5' + spec.summary = spec.description + spec.version = "0.2.0" +end diff --git a/.gems/gems/buftok-0.2.0/lib/buftok.rb b/.gems/gems/buftok-0.2.0/lib/buftok.rb new file mode 100644 index 0000000..caf4f77 --- /dev/null +++ b/.gems/gems/buftok-0.2.0/lib/buftok.rb @@ -0,0 +1,59 @@ +# BufferedTokenizer takes a delimiter upon instantiation, or acts line-based +# by default. It allows input to be spoon-fed from some outside source which +# receives arbitrary length datagrams which may-or-may-not contain the token +# by which entities are delimited. In this respect it's ideally paired with +# something like EventMachine (http://rubyeventmachine.com/). +class BufferedTokenizer + # New BufferedTokenizers will operate on lines delimited by a delimiter, + # which is by default the global input delimiter $/ ("\n"). + # + # The input buffer is stored as an array. This is by far the most efficient + # approach given language constraints (in C a linked list would be a more + # appropriate data structure). Segments of input data are stored in a list + # which is only joined when a token is reached, substantially reducing the + # number of objects required for the operation. + def initialize(delimiter = $/) + @delimiter = delimiter + @input = [] + @tail = '' + @trim = @delimiter.length - 1 + end + + # Extract takes an arbitrary string of input data and returns an array of + # tokenized entities, provided there were any available to extract. This + # makes for easy processing of datagrams using a pattern like: + # + # tokenizer.extract(data).map { |entity| Decode(entity) }.each do ... + # + # Using -1 makes split to return "" if the token is at the end of + # the string, meaning the last element is the start of the next chunk. + def extract(data) + if @trim > 0 + tail_end = @tail.slice!(-@trim, @trim) # returns nil if string is too short + data = tail_end + data if tail_end + end + + @input << @tail + entities = data.split(@delimiter, -1) + @tail = entities.shift + + unless entities.empty? + @input << @tail + entities.unshift @input.join + @input.clear + @tail = entities.pop + end + + entities + end + + # Flush the contents of the input buffer, i.e. return the input buffer even though + # a token has not yet been encountered + def flush + @input << @tail + buffer = @input.join + @input.clear + @tail = "" # @tail.clear is slightly faster, but not supported on 1.8.7 + buffer + end +end diff --git a/.gems/gems/buftok-0.2.0/test/test_buftok.rb b/.gems/gems/buftok-0.2.0/test/test_buftok.rb new file mode 100644 index 0000000..535b362 --- /dev/null +++ b/.gems/gems/buftok-0.2.0/test/test_buftok.rb @@ -0,0 +1,27 @@ +require 'test/unit' +require 'buftok' + +class TestBuftok < Test::Unit::TestCase + def test_buftok + tokenizer = BufferedTokenizer.new + assert_equal %w[foo], tokenizer.extract("foo\nbar".freeze) + assert_equal %w[barbaz qux], tokenizer.extract("baz\nqux\nquu".freeze) + assert_equal 'quu', tokenizer.flush + assert_equal '', tokenizer.flush + end + + def test_delimiter + tokenizer = BufferedTokenizer.new('<>') + assert_equal ['', "foo\n"], tokenizer.extract("<>foo\n<>".freeze) + assert_equal %w[bar], tokenizer.extract('bar<>baz'.freeze) + assert_equal 'baz', tokenizer.flush + end + + def test_split_delimiter + tokenizer = BufferedTokenizer.new('<>'.freeze) + assert_equal [], tokenizer.extract('foo<'.freeze) + assert_equal %w[foo], tokenizer.extract('>bar<'.freeze) + assert_equal %w[barqux<>'.freeze) + assert_equal '', tokenizer.flush + end +end diff --git a/.gems/gems/equalizer-0.0.9/.gitignore b/.gems/gems/equalizer-0.0.9/.gitignore new file mode 100644 index 0000000..b98eb63 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.gitignore @@ -0,0 +1,37 @@ +## MAC OS +.DS_Store + +## TEXTMATE +*.tmproj +tmtags + +## EMACS +*~ +\#* +.\#* + +## VIM +*.swp + +## Rubinius +*.rbc +.rbx + +## PROJECT::GENERAL +*.gem +coverage +profiling +turbulence +rdoc +pkg +tmp +doc +log +.yardoc +measurements + +## BUNDLER +.bundle +Gemfile.lock + +## PROJECT::SPECIFIC diff --git a/.gems/gems/equalizer-0.0.9/.reek.yml b/.gems/gems/equalizer-0.0.9/.reek.yml new file mode 100644 index 0000000..7111519 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.reek.yml @@ -0,0 +1,106 @@ +--- +Attribute: + enabled: true + exclude: [] +BooleanParameter: + enabled: true + exclude: [] +ClassVariable: + enabled: true + exclude: [] +ControlParameter: + enabled: true + exclude: [] +DataClump: + enabled: true + exclude: [] + max_copies: 2 + min_clump_size: 2 +DuplicateMethodCall: + enabled: true + exclude: [] + max_calls: 1 + allow_calls: [] +FeatureEnvy: + enabled: true + exclude: [] +IrresponsibleModule: + enabled: true + exclude: [] +LongParameterList: + enabled: true + exclude: [] + max_params: 2 + overrides: + initialize: + max_params: 3 +LongYieldList: + enabled: true + exclude: [] + max_params: 2 +NestedIterators: + enabled: true + exclude: + - Equalizer#define_cmp_method + - Equalizer#define_hash_method + - Equalizer#define_inspect_method + max_allowed_nesting: 1 + ignore_iterators: [] +NilCheck: + enabled: true + exclude: [] +RepeatedConditional: + enabled: true + exclude: [] + max_ifs: 1 +TooManyInstanceVariables: + enabled: true + exclude: [] + max_instance_variables: 3 +TooManyMethods: + enabled: true + exclude: [] + max_methods: 10 +TooManyStatements: + enabled: true + exclude: + - each + max_statements: 5 +UncommunicativeMethodName: + enabled: true + exclude: [] + reject: + - !ruby/regexp /^[a-z]$/ + - !ruby/regexp /[0-9]$/ + - !ruby/regexp /[A-Z]/ + accept: [] +UncommunicativeModuleName: + enabled: true + exclude: [] + reject: + - !ruby/regexp /^.$/ + - !ruby/regexp /[0-9]$/ + accept: [] +UncommunicativeParameterName: + enabled: true + exclude: [] + reject: + - !ruby/regexp /^.$/ + - !ruby/regexp /[0-9]$/ + - !ruby/regexp /[A-Z]/ + accept: [] +UncommunicativeVariableName: + enabled: true + exclude: [] + reject: + - !ruby/regexp /^.$/ + - !ruby/regexp /[0-9]$/ + - !ruby/regexp /[A-Z]/ + accept: [] +UnusedParameters: + enabled: true + exclude: [] +UtilityFunction: + enabled: true + exclude: [] + max_helper_calls: 0 diff --git a/.gems/gems/equalizer-0.0.9/.rspec b/.gems/gems/equalizer-0.0.9/.rspec new file mode 100644 index 0000000..5e712d3 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.rspec @@ -0,0 +1,5 @@ +--color +--format progress +--profile +--warnings +--order random diff --git a/.gems/gems/equalizer-0.0.9/.rubocop.yml b/.gems/gems/equalizer-0.0.9/.rubocop.yml new file mode 100644 index 0000000..4935186 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.rubocop.yml @@ -0,0 +1,69 @@ +AllCops: + Includes: + - '**/*.rake' + - 'Gemfile' + - 'Rakefile' + Excludes: + - 'vendor/**' + +# Avoid parameter lists longer than five parameters. +ParameterLists: + Max: 3 + CountKeywordArgs: true + +# Avoid more than `Max` levels of nesting. +BlockNesting: + Max: 3 + +# Align with the style guide. +CollectionMethods: + PreferredMethods: + collect: 'map' + inject: 'reduce' + find: 'detect' + find_all: 'select' + +# Do not force public/protected/private keyword to be indented at the same +# level as the def keyword. My personal preference is to outdent these keywords +# because I think when scanning code it makes it easier to identify the +# sections of code and visually separate them. When the keyword is at the same +# level I think it sort of blends in with the def keywords and makes it harder +# to scan the code and see where the sections are. +AccessModifierIndentation: + Enabled: false + +# Disable documentation checking until a class needs to be documented once +Documentation: + Enabled: false + +# Do not always use &&/|| instead of and/or. +AndOr: + Enabled: false + +# Do not favor modifier if/unless usage when you have a single-line body +IfUnlessModifier: + Enabled: false + +# Allow case equality operator (in limited use within the specs) +CaseEquality: + Enabled: false + +# Constants do not always have to use SCREAMING_SNAKE_CASE +ConstantName: + Enabled: false + +# Not all trivial readers/writers can be defined with attr_* methods +TrivialAccessors: + Enabled: false + +# Allow empty lines around body +EmptyLinesAroundBody: + Enabled: false + +# Enforce Ruby 1.8-compatible hash syntax +HashSyntax: + EnforcedStyle: hash_rockets + +# Allow dots at the end of lines +DotPosition: + Enabled: false diff --git a/.gems/gems/equalizer-0.0.9/.ruby-gemset b/.gems/gems/equalizer-0.0.9/.ruby-gemset new file mode 100644 index 0000000..c013490 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.ruby-gemset @@ -0,0 +1 @@ +equalizer diff --git a/.gems/gems/equalizer-0.0.9/.travis.yml b/.gems/gems/equalizer-0.0.9/.travis.yml new file mode 100644 index 0000000..e7c6aef --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.travis.yml @@ -0,0 +1,29 @@ +language: ruby +cache: bundler +bundler_args: --without yard guard benchmarks +script: "bundle exec rake ci" +rvm: + - ree + - 1.8.7 + - 1.9.2 + - 1.9.3 + - 2.0.0 + - ruby-head + - rbx +matrix: + include: + - rvm: jruby-18mode + env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov + - rvm: jruby-19mode + env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov + - rvm: jruby-20mode + env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov + - rvm: jruby-head + env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov + fast_finish: true +notifications: + irc: + channels: + - irc.freenode.org#rom-rb + on_success: never + on_failure: change diff --git a/.gems/gems/equalizer-0.0.9/.yardstick.yml b/.gems/gems/equalizer-0.0.9/.yardstick.yml new file mode 100644 index 0000000..a6b63e8 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/.yardstick.yml @@ -0,0 +1,2 @@ +--- +threshold: 100 diff --git a/.gems/gems/equalizer-0.0.9/CONTRIBUTING.md b/.gems/gems/equalizer-0.0.9/CONTRIBUTING.md new file mode 100644 index 0000000..333b403 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/CONTRIBUTING.md @@ -0,0 +1,11 @@ +Contributing +------------ + +* If you want your code merged into the mainline, please discuss the proposed changes with me before doing any work on it. This library is still in early development, and the direction it is going may not always be clear. Some features may not be appropriate yet, may need to be deferred until later when the foundation for them is laid, or may be more applicable in a plugin. +* Fork the project. +* Make your feature addition or bug fix. + * Follow this [style guide](https://github.com/dkubb/styleguide). +* Add specs for it. This is important so I don't break it in a future version unintentionally. Tests must cover all branches within the code, and code must be fully covered. +* Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) +* Run "rake ci". This must pass and not show any regressions in the metrics for the code to be merged. +* Send me a pull request. Bonus points for topic branches. diff --git a/.gems/gems/equalizer-0.0.9/Gemfile b/.gems/gems/equalizer-0.0.9/Gemfile new file mode 100644 index 0000000..633eefc --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/Gemfile @@ -0,0 +1,28 @@ +# encoding: utf-8 + +source 'https://rubygems.org' + +gem 'rake' + +group :test do + gem 'backports' + gem 'coveralls', :require => false + gem 'json', :platforms => [:ruby_19] + gem 'reek' + gem 'rspec', '~> 2.14' + gem 'rubocop', :platforms => [:ruby_19, :ruby_20] + gem 'simplecov', :require => false + gem 'yardstick' +end + +platforms :jruby, :ruby_18 do + gem 'mime-types', '~> 1.25' +end + +platforms :rbx do + gem 'racc' + gem 'rubinius-coverage', '~> 2.0' + gem 'rubysl', '~> 2.0' +end + +gemspec diff --git a/.gems/gems/equalizer-0.0.9/LICENSE b/.gems/gems/equalizer-0.0.9/LICENSE new file mode 100644 index 0000000..18b962b --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2009-2013 Dan Kubb +Copyright (c) 2012 Markus Schirp (packaging) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/equalizer-0.0.9/README.md b/.gems/gems/equalizer-0.0.9/README.md new file mode 100644 index 0000000..056a7fe --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/README.md @@ -0,0 +1,97 @@ +equalizer +========= + +Module to define equality, equivalence and inspection methods + +[![Gem Version](https://badge.fury.io/rb/equalizer.png)][gem] +[![Build Status](https://secure.travis-ci.org/dkubb/equalizer.png?branch=master)][travis] +[![Dependency Status](https://gemnasium.com/dkubb/equalizer.png)][gemnasium] +[![Code Climate](https://codeclimate.com/github/dkubb/equalizer.png)][codeclimate] +[![Coverage Status](https://coveralls.io/repos/dkubb/equalizer/badge.png?branch=master)][coveralls] + +[gem]: https://rubygems.org/gems/equalizer +[travis]: https://travis-ci.org/dkubb/equalizer +[gemnasium]: https://gemnasium.com/dkubb/equalizer +[codeclimate]: https://codeclimate.com/github/dkubb/equalizer +[coveralls]: https://coveralls.io/r/dkubb/equalizer + +Examples +-------- + +``` ruby +class GeoLocation + include Equalizer.new(:latitude, :longitude) + + attr_reader :latitude, :longitude + + def initialize(latitude, longitude) + @latitude, @longitude = latitude, longitude + end +end + +point_a = GeoLocation.new(1, 2) +point_b = GeoLocation.new(1, 2) +point_c = GeoLocation.new(2, 2) + +point_a.inspect # => "#" + +point_a == point_b # => true +point_a.hash == point_b.hash # => true +point_a.eql?(point_b) # => true +point_a.equal?(point_b) # => false + +point_a == point_c # => false +point_a.hash == point_c.hash # => false +point_a.eql?(point_c) # => false +point_a.equal?(point_c) # => false +``` + +Supported Ruby Versions +----------------------- + +This library aims to support and is [tested against][travis] the following Ruby +implementations: + +* Ruby 1.8.7 +* Ruby 1.9.2 +* Ruby 1.9.3 +* Ruby 2.0.0 +* [JRuby][] +* [Rubinius][] +* [Ruby Enterprise Edition][ree] + +[jruby]: http://jruby.org/ +[rubinius]: http://rubini.us/ +[ree]: http://www.rubyenterpriseedition.com/ + +If something doesn't work on one of these versions, it's a bug. + +This library may inadvertently work (or seem to work) on other Ruby versions or +implementations, however support will only be provided for the implementations +listed above. + +If you would like this library to support another Ruby version or +implementation, you may volunteer to be a maintainer. Being a maintainer +entails making sure all tests run and pass on that implementation. When +something breaks on your implementation, you will be responsible for providing +patches in a timely fashion. If critical issues for a particular implementation +exist at the time of a major release, support for that Ruby version may be +dropped. + +Credits +------- + +* Dan Kubb ([dkubb](https://github.com/dkubb)) +* Piotr Solnica ([solnic](https://github.com/solnic)) +* Markus Schirp ([mbj](https://github.com/mbj)) +* Erik Michaels-Ober ([sferik](https://github.com/sferik)) + +Contributing +------------- + +See [CONTRIBUTING.md](CONTRIBUTING.md) for details. + +Copyright +--------- + +Copyright © 2009-2013 Dan Kubb. See LICENSE for details. diff --git a/.gems/gems/equalizer-0.0.9/Rakefile b/.gems/gems/equalizer-0.0.9/Rakefile new file mode 100644 index 0000000..2da2334 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/Rakefile @@ -0,0 +1,39 @@ +# encoding: utf-8 + +require 'bundler' +Bundler::GemHelper.install_tasks + +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new(:spec) + +task :test => :spec +task :default => :spec + +require 'reek/rake/task' +Reek::Rake::Task.new do |reek| + reek.reek_opts = '--quiet' + reek.fail_on_error = true + reek.config_files = '.reek.yml' +end + +begin + require 'rubocop/rake_task' + Rubocop::RakeTask.new +rescue LoadError + desc 'Run RuboCop' + task :rubocop do + $stderr.puts 'Rubocop is disabled' + end +end + +require 'yardstick/rake/measurement' +Yardstick::Rake::Measurement.new do |measurement| + measurement.output = 'measurement/report.txt' +end + +require 'yardstick/rake/verify' +Yardstick::Rake::Verify.new do |verify| + verify.threshold = 100 +end + +task :ci => [:spec, :rubocop, :reek, :verify_measurements] diff --git a/.gems/gems/equalizer-0.0.9/equalizer.gemspec b/.gems/gems/equalizer-0.0.9/equalizer.gemspec new file mode 100644 index 0000000..9f9933f --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/equalizer.gemspec @@ -0,0 +1,21 @@ +# encoding: utf-8 + +require File.expand_path('../lib/equalizer/version', __FILE__) + +Gem::Specification.new do |gem| + gem.name = 'equalizer' + gem.version = Equalizer::VERSION.dup + gem.authors = ['Dan Kubb', 'Markus Schirp'] + gem.email = %w[dan.kubb@gmail.com mbj@schirp-dso.com] + gem.description = 'Module to define equality, equivalence and inspection methods' + gem.summary = gem.description + gem.homepage = 'https://github.com/dkubb/equalizer' + gem.licenses = 'MIT' + + gem.require_paths = %w[lib] + gem.files = `git ls-files`.split("\n") + gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n") + gem.extra_rdoc_files = %w[LICENSE README.md CONTRIBUTING.md] + + gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5') +end diff --git a/.gems/gems/equalizer-0.0.9/lib/equalizer.rb b/.gems/gems/equalizer-0.0.9/lib/equalizer.rb new file mode 100644 index 0000000..833901b --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/lib/equalizer.rb @@ -0,0 +1,122 @@ +# encoding: utf-8 + +# Define equality, equivalence and inspection methods +class Equalizer < Module + + # Initialize an Equalizer with the given keys + # + # Will use the keys with which it is initialized to define #cmp?, + # #hash, and #inspect + # + # @param [Array] keys + # + # @return [undefined] + # + # @api private + def initialize(*keys) + @keys = keys + define_methods + freeze + end + +private + + # Hook called when module is included + # + # @param [Module] descendant + # the module or class including Equalizer + # + # @return [self] + # + # @api private + def included(descendant) + super + descendant.module_eval { include Methods } + end + + # Define the equalizer methods based on #keys + # + # @return [undefined] + # + # @api private + def define_methods + define_cmp_method + define_hash_method + define_inspect_method + end + + # Define an #cmp? method based on the instance's values identified by #keys + # + # @return [undefined] + # + # @api private + def define_cmp_method + keys = @keys + define_method(:cmp?) do |comparator, other| + keys.all? { |key| send(key).send(comparator, other.send(key)) } + end + private :cmp? + end + + # Define a #hash method based on the instance's values identified by #keys + # + # @return [undefined] + # + # @api private + def define_hash_method + keys = @keys + define_method(:hash) do || + keys.map(&method(:send)).push(self.class).hash + end + end + + # Define an inspect method that reports the values of the instance's keys + # + # @return [undefined] + # + # @api private + def define_inspect_method + keys = @keys + define_method(:inspect) do || + klass = self.class + name = klass.name || klass.inspect + "#<#{name}#{keys.map { |key| " #{key}=#{send(key).inspect}" }.join}>" + end + end + + # The comparison methods + module Methods + + # Compare the object with other object for equality + # + # @example + # object.eql?(other) # => true or false + # + # @param [Object] other + # the other object to compare with + # + # @return [Boolean] + # + # @api public + def eql?(other) + instance_of?(other.class) && cmp?(__method__, other) + end + + # Compare the object with other object for equivalency + # + # @example + # object == other # => true or false + # + # @param [Object] other + # the other object to compare with + # + # @return [Boolean] + # + # @api public + def ==(other) + other = coerce(other) if respond_to?(:coerce, true) + other.kind_of?(self.class) && cmp?(__method__, other) + end + + end # module Methods +end # class Equalizer diff --git a/.gems/gems/equalizer-0.0.9/lib/equalizer/version.rb b/.gems/gems/equalizer-0.0.9/lib/equalizer/version.rb new file mode 100644 index 0000000..1451289 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/lib/equalizer/version.rb @@ -0,0 +1,8 @@ +# encoding: utf-8 + +class Equalizer < Module + + # Gem version + VERSION = '0.0.9'.freeze + +end # class Equalizer diff --git a/.gems/gems/equalizer-0.0.9/spec/spec_helper.rb b/.gems/gems/equalizer-0.0.9/spec/spec_helper.rb new file mode 100644 index 0000000..045a60b --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/spec/spec_helper.rb @@ -0,0 +1,34 @@ +# encoding: utf-8 + +if ENV['COVERAGE'] == 'true' + require 'simplecov' + require 'coveralls' + + SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter, + ] + + SimpleCov.start do + command_name 'spec:unit' + + add_filter 'config' + add_filter 'spec' + add_filter 'vendor' + + minimum_coverage 100 + end +end + +require 'equalizer' + +# TODO: FIXME! +# Cache correct freezer in ice_nine before +# rspec2 infects the world... +Equalizer.new + +RSpec.configure do |config| + config.expect_with :rspec do |expect_with| + expect_with.syntax = :expect + end +end diff --git a/.gems/gems/equalizer-0.0.9/spec/support/config_alias.rb b/.gems/gems/equalizer-0.0.9/spec/support/config_alias.rb new file mode 100644 index 0000000..9c3f42f --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/spec/support/config_alias.rb @@ -0,0 +1,5 @@ +# encoding: utf-8 + +require 'rbconfig' + +::Config = RbConfig unless defined?(::Config) diff --git a/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/included_spec.rb b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/included_spec.rb new file mode 100644 index 0000000..229da6f --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/included_spec.rb @@ -0,0 +1,40 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Equalizer, '#included' do + subject { descendant.instance_exec(object) { |mod| include mod } } + + let(:object) { described_class.new } + let(:descendant) { Class.new } + let(:superclass) { described_class.superclass } + + before do + # Prevent Module.included from being called through inheritance + described_class::Methods.stub(:included) + end + + around do |example| + # Restore included method after each example + superclass.class_eval do + alias_method :original_included, :included + example.call + undef_method :included + alias_method :included, :original_included + end + end + + it 'delegates to the superclass #included method' do + # This is the most succinct approach I could think of to test whether the + # superclass#included method is called. All of the built-in rspec helpers + # did not seem to work for this. + included = false + superclass.class_eval { define_method(:included) { |_| included = true } } + expect { subject }.to change { included }.from(false).to(true) + end + + it 'includes methods into the descendant' do + subject + expect(descendant.included_modules).to include(described_class::Methods) + end +end diff --git a/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/eql_predicate_spec.rb b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/eql_predicate_spec.rb new file mode 100644 index 0000000..774eb5f --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/eql_predicate_spec.rb @@ -0,0 +1,65 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Equalizer::Methods, '#eql?' do + subject { object.eql?(other) } + + let(:object) { described_class.new(true) } + + let(:described_class) do + Class.new do + include Equalizer::Methods + + attr_reader :boolean + + def initialize(boolean) + @boolean = boolean + end + + def cmp?(comparator, other) + boolean.send(comparator, other.boolean) + end + end + end + + context 'with the same object' do + let(:other) { object } + + it { should be(true) } + + it 'is symmetric' do + should eql(other.eql?(object)) + end + end + + context 'with an equivalent object' do + let(:other) { object.dup } + + it { should be(true) } + + it 'is symmetric' do + should eql(other.eql?(object)) + end + end + + context 'with an equivalent object of a subclass' do + let(:other) { Class.new(described_class).new(true) } + + it { should be(false) } + + it 'is symmetric' do + should eql(other.eql?(object)) + end + end + + context 'with a different object' do + let(:other) { described_class.new(false) } + + it { should be(false) } + + it 'is symmetric' do + should eql(other.eql?(object)) + end + end +end diff --git a/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/equality_operator_spec.rb b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/equality_operator_spec.rb new file mode 100644 index 0000000..e08b90c --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/methods/equality_operator_spec.rb @@ -0,0 +1,108 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Equalizer::Methods, '#==' do + subject { object == other } + + let(:object) { described_class.new(true) } + let(:described_class) { Class.new(super_class) } + + let(:super_class) do + Class.new do + include Equalizer::Methods + + attr_reader :boolean + + def initialize(boolean) + @boolean = boolean + end + + def cmp?(comparator, other) + boolean.send(comparator, other.boolean) + end + end + end + + context 'with the same object' do + let(:other) { object } + + it { should be(true) } + + it 'is symmetric' do + should eql(other == object) + end + end + + context 'with an equivalent object' do + let(:other) { object.dup } + + it { should be(true) } + + it 'is symmetric' do + should eql(other == object) + end + end + + context 'with a subclass instance having equivalent obervable state' do + let(:other) { Class.new(described_class).new(true) } + + it { should be(true) } + + it 'is not symmetric' do + # the subclass instance should maintain substitutability with the object + # (in the LSP sense) the reverse is not true. + should_not eql(other == object) + end + end + + context 'with a superclass instance having equivalent observable state' do + let(:other) { super_class.new(true) } + + it { should be(false) } + + it 'is not symmetric' do + should_not eql(other == object) + end + end + + context 'with an object of another class' do + let(:other) { Class.new.new } + + it { should be(false) } + + it 'is symmetric' do + should eql(other == object) + end + end + + context 'with an equivalent object after coercion' do + let(:other) { Object.new } + + before do + # declare a private #coerce method + described_class.class_eval do + def coerce(other) + self.class.new(!!other) + end + private :coerce + end + end + + it { should be(true) } + + it 'is not symmetric' do + should_not eql(other == object) + end + end + + context 'with a different object' do + let(:other) { described_class.new(false) } + + it { should be(false) } + + it 'is symmetric' do + should eql(other == object) + end + end +end diff --git a/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/universal_spec.rb b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/universal_spec.rb new file mode 100644 index 0000000..0549e04 --- /dev/null +++ b/.gems/gems/equalizer-0.0.9/spec/unit/equalizer/universal_spec.rb @@ -0,0 +1,159 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Equalizer, '.new' do + + let(:object) { described_class } + let(:name) { 'User' } + let(:klass) { ::Class.new } + + context 'with no keys' do + subject { object.new } + + before do + # specify the class #name method + klass.stub(:name).and_return(name) + klass.send(:include, subject) + end + + let(:instance) { klass.new } + + it { should be_instance_of(object) } + + it { should be_frozen } + + it 'defines #hash and #inspect methods dynamically' do + expect(subject.public_instance_methods(false).map(&:to_s).sort). + to eql(%w[hash inspect]) + end + + describe '#eql?' do + context 'when the objects are similar' do + let(:other) { instance.dup } + + it { expect(instance.eql?(other)).to be(true) } + end + + context 'when the objects are different' do + let(:other) { double('other') } + + it { expect(instance.eql?(other)).to be(false) } + end + end + + describe '#==' do + context 'when the objects are similar' do + let(:other) { instance.dup } + + it { expect(instance == other).to be(true) } + end + + context 'when the objects are different' do + let(:other) { double('other') } + + it { expect(instance == other).to be(false) } + end + end + + describe '#hash' do + it 'has the expected arity' do + expect(klass.instance_method(:hash).arity).to be(0) + end + + it { expect(instance.hash).to eql([klass].hash) } + end + + describe '#inspect' do + it 'has the expected arity' do + expect(klass.instance_method(:inspect).arity).to be(0) + end + + it { expect(instance.inspect).to eql('#') } + end + end + + context 'with keys' do + subject { object.new(*keys) } + + let(:keys) { [:firstname, :lastname].freeze } + let(:firstname) { 'John' } + let(:lastname) { 'Doe' } + let(:instance) { klass.new(firstname, lastname) } + + let(:klass) do + ::Class.new do + attr_reader :firstname, :lastname + private :firstname, :lastname + + def initialize(firstname, lastname) + @firstname, @lastname = firstname, lastname + end + end + end + + before do + # specify the class #inspect method + klass.stub(:name).and_return(nil) + klass.stub(:inspect).and_return(name) + klass.send(:include, subject) + end + + it { should be_instance_of(object) } + + it { should be_frozen } + + it 'defines #hash and #inspect methods dynamically' do + expect(subject.public_instance_methods(false).map(&:to_s).sort). + to eql(%w[ hash inspect ]) + end + + describe '#eql?' do + context 'when the objects are similar' do + let(:other) { instance.dup } + + it { expect(instance.eql?(other)).to be(true) } + end + + context 'when the objects are different' do + let(:other) { double('other') } + + it { expect(instance.eql?(other)).to be(false) } + end + end + + describe '#==' do + context 'when the objects are similar' do + let(:other) { instance.dup } + + it { expect(instance == other).to be(true) } + end + + context 'when the objects are different type' do + let(:other) { klass.new('Foo', 'Bar') } + + it { expect(instance == other).to be(false) } + end + + context 'when the objects are from different type' do + let(:other) { double('other') } + + it { expect(instance == other).to be(false) } + end + end + + describe '#hash' do + it 'returns the expected hash' do + expect(instance.hash). + to eql([firstname, lastname, klass].hash) + end + end + + describe '#inspect' do + it 'returns the expected string' do + expect(instance.inspect). + to eql('#') + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/.document b/.gems/gems/faraday-0.9.0/.document new file mode 100644 index 0000000..1fd4b83 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/.document @@ -0,0 +1,6 @@ +CONTRIBUTING.md +LICENSE.md +README.md +bin/* +lib/**/*.rb +test/**/*.rb diff --git a/.gems/gems/faraday-0.9.0/CHANGELOG.md b/.gems/gems/faraday-0.9.0/CHANGELOG.md new file mode 100644 index 0000000..650ba1d --- /dev/null +++ b/.gems/gems/faraday-0.9.0/CHANGELOG.md @@ -0,0 +1,15 @@ +# Faraday Changelog + +## v0.9.0 + +* Add HTTPClient adapter (@hakanensari) +* Improve Retry handler (@mislav) +* Remove autoloading by default (@technoweenie) +* Improve internal docs (@technoweenie, @mislav) +* Respect user/password in http proxy string (@mislav) +* Adapter options are structs. Reinforces consistent options across adapters + (@technoweenie) +* Stop stripping trailing / off base URLs in a Faraday::Connection. (@technoweenie) +* Add a configurable URI parser. (@technoweenie) +* Remove need to manually autoload when using the authorization header helpers on `Faraday::Connection`. (@technoweenie) +* `Faraday::Adapter::Test` respects the `Faraday::RequestOptions#params_encoder` option. (@technoweenie) diff --git a/.gems/gems/faraday-0.9.0/CONTRIBUTING.md b/.gems/gems/faraday-0.9.0/CONTRIBUTING.md new file mode 100644 index 0000000..63bdf29 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/CONTRIBUTING.md @@ -0,0 +1,36 @@ +## Contributing + +You can run the test suite against a live server by running `script/test`. It +automatically starts a test server in background. Only tests in +`test/adapters/*_test.rb` require a server, though. + +``` sh +# run the whole suite +$ script/test + +# run only specific files +$ script/test excon typhoeus + +# run tests using SSL +$ SSL=yes script/test +``` + +We will accept middleware that: + +1. is useful to a broader audience, but can be implemented relatively + simple; and +2. which isn't already present in [faraday_middleware][] project. + +We will accept adapters that: + +1. support SSL & streaming; +1. are proven and may have better performance than existing ones; or +2. if they have features not present in included adapters. + +We are pushing towards a 1.0 release, when we will have to follow [Semantic +Versioning][semver]. If your patch includes changes to break compatiblitity, +note that so we can add it to the [Changelog][]. + +[semver]: http://semver.org/ +[changelog]: https://github.com/technoweenie/faraday/wiki/Changelog +[faraday_middleware]: https://github.com/pengwynn/faraday_middleware/wiki diff --git a/.gems/gems/faraday-0.9.0/Gemfile b/.gems/gems/faraday-0.9.0/Gemfile new file mode 100644 index 0000000..8824eb6 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/Gemfile @@ -0,0 +1,29 @@ +source 'https://rubygems.org' + +gem 'ffi-ncurses', '~> 0.3', :platforms => :jruby +gem 'jruby-openssl', '~> 0.8.8', :platforms => :jruby +gem 'rake' + +group :test do + gem 'coveralls', :require => false + gem 'em-http-request', '>= 1.1', :require => 'em-http' + gem 'em-synchrony', '>= 1.0.3', :require => ['em-synchrony', 'em-synchrony/em-http'] + gem 'excon', '>= 0.27.4' + gem 'httpclient', '>= 2.2' + gem 'leftright', '>= 0.9', :require => false + gem 'mime-types', '~> 1.25', :platforms => [:jruby, :ruby_18] + gem 'minitest', '>= 5.0.5' + gem 'net-http-persistent', '>= 2.5', :require => false + gem 'patron', '>= 0.4.2', :platforms => :ruby + gem 'rack-test', '>= 0.6', :require => 'rack/test' + gem 'simplecov' + gem 'sinatra', '~> 1.3' + gem 'typhoeus', '~> 0.3.3', :platforms => :ruby +end + +platforms :rbx do + gem 'rubinius-coverage' + gem 'rubysl' +end + +gemspec diff --git a/.gems/gems/faraday-0.9.0/LICENSE.md b/.gems/gems/faraday-0.9.0/LICENSE.md new file mode 100644 index 0000000..98dc016 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2009-2013 Rick Olson, Zack Hobson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/faraday-0.9.0/README.md b/.gems/gems/faraday-0.9.0/README.md new file mode 100644 index 0000000..e59d09d --- /dev/null +++ b/.gems/gems/faraday-0.9.0/README.md @@ -0,0 +1,216 @@ +# Faraday + +Faraday is an HTTP client lib that provides a common interface over many +adapters (such as Net::HTTP) and embraces the concept of Rack middleware when +processing the request/response cycle. + +Faraday supports these adapters: + +* Net::HTTP +* [Excon][] +* [Typhoeus][] +* [Patron][] +* [EventMachine][] + +It also includes a Rack adapter for hitting loaded Rack applications through +Rack::Test, and a Test adapter for stubbing requests by hand. + +## Usage + +```ruby +conn = Faraday.new(:url => 'http://sushi.com') do |faraday| + faraday.request :url_encoded # form-encode POST params + faraday.response :logger # log requests to STDOUT + faraday.adapter Faraday.default_adapter # make requests with Net::HTTP +end + +## GET ## + +response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json +response.body + +conn.get '/nigiri', { :name => 'Maguro' } # GET /nigiri?name=Maguro + +conn.get do |req| # GET http://sushi.com/search?page=2&limit=100 + req.url '/search', :page => 2 + req.params['limit'] = 100 +end + +## POST ## + +conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri + +# post payload as JSON instead of "www-form-urlencoded" encoding: +conn.post do |req| + req.url '/nigiri' + req.headers['Content-Type'] = 'application/json' + req.body = '{ "name": "Unagi" }' +end + +## Per-request options ## + +conn.get do |req| + req.url '/search' + req.options.timeout = 5 # open/read timeout in seconds + req.options.open_timeout = 2 # connection open timeout in seconds +end +``` + +If you don't need to set up anything, you can roll with just the bare minimum: + +```ruby +# using the default stack: +response = Faraday.get 'http://sushi.com/nigiri/sake.json' +``` + +## Advanced middleware usage + +The order in which middleware is stacked is important. Like with Rack, the +first middleware on the list wraps all others, while the last middleware is the +innermost one, so that must be the adapter. + +```ruby +Faraday.new(...) do |conn| + # POST/PUT params encoders: + conn.request :multipart + conn.request :url_encoded + + conn.adapter :net_http +end +``` + +This request middleware setup affects POST/PUT requests in the following way: + +1. `Request::Multipart` checks for files in the payload, otherwise leaves + everything untouched; +2. `Request::UrlEncoded` encodes as "application/x-www-form-urlencoded" if not + already encoded or of another type + +Swapping middleware means giving the other priority. Specifying the +"Content-Type" for the request is explicitly stating which middleware should +process it. + +Examples: + +```ruby +# uploading a file: +payload[:profile_pic] = Faraday::UploadIO.new('/path/to/avatar.jpg', 'image/jpeg') + +# "Multipart" middleware detects files and encodes with "multipart/form-data": +conn.put '/profile', payload +``` + +## Writing middleware + +Middleware are classes that implement a `call` instance method. They hook into +the request/response cycle. + +```ruby +def call(env) + # do something with the request + + @app.call(env).on_complete do + # do something with the response + end +end +``` + +It's important to do all processing of the response only in the `on_complete` +block. This enables middleware to work in parallel mode where requests are +asynchronous. + +The `env` is a hash with symbol keys that contains info about the request and, +later, response. Some keys are: + +``` +# request phase +:method - :get, :post, ... +:url - URI for the current request; also contains GET parameters +:body - POST parameters for :post/:put requests +:request_headers + +# response phase +:status - HTTP response status code, such as 200 +:body - the response body +:response_headers +``` + +## Using Faraday for testing + +```ruby +# It's possible to define stubbed request outside a test adapter block. +stubs = Faraday::Adapter::Test::Stubs.new do |stub| + stub.get('/tamago') { [200, {}, 'egg'] } +end + +# You can pass stubbed request to the test adapter or define them in a block +# or a combination of the two. +test = Faraday.new do |builder| + builder.adapter :test, stubs do |stub| + stub.get('/ebi') {[ 200, {}, 'shrimp' ]} + end +end + +# It's also possible to stub additional requests after the connection has +# been initialized. This is useful for testing. +stubs.get('/uni') {[ 200, {}, 'urchin' ]} + +resp = test.get '/tamago' +resp.body # => 'egg' +resp = test.get '/ebi' +resp.body # => 'shrimp' +resp = test.get '/uni' +resp.body # => 'urchin' +resp = test.get '/else' #=> raises "no such stub" error + +# If you like, you can treat your stubs as mocks by verifying that all of +# the stubbed calls were made. NOTE that this feature is still fairly +# experimental: It will not verify the order or count of any stub, only that +# it was called once during the course of the test. +stubs.verify_stubbed_calls +``` + +## TODO + +* support streaming requests/responses +* better stubbing API + +## Supported Ruby versions + +This library aims to support and is [tested against][travis] the following Ruby +implementations: + +* MRI 1.8.7 +* MRI 1.9.2 +* MRI 1.9.3 +* MRI 2.0.0 +* MRI 2.1.0 +* [JRuby][] +* [Rubinius][] + +If something doesn't work on one of these Ruby versions, it's a bug. + +This library may inadvertently work (or seem to work) on other Ruby +implementations, however support will only be provided for the versions listed +above. + +If you would like this library to support another Ruby version, you may +volunteer to be a maintainer. Being a maintainer entails making sure all tests +run and pass on that implementation. When something breaks on your +implementation, you will be responsible for providing patches in a timely +fashion. If critical issues for a particular implementation exist at the time +of a major release, support for that Ruby version may be dropped. + +## Copyright + +Copyright (c) 2009-2013 [Rick Olson](mailto:technoweenie@gmail.com), Zack Hobson. +See [LICENSE][] for details. + +[travis]: http://travis-ci.org/lostisland/faraday +[excon]: https://github.com/geemus/excon#readme +[typhoeus]: https://github.com/typhoeus/typhoeus#readme +[patron]: http://toland.github.com/patron/ +[eventmachine]: https://github.com/igrigorik/em-http-request#readme +[jruby]: http://jruby.org/ +[rubinius]: http://rubini.us/ +[license]: LICENSE.md diff --git a/.gems/gems/faraday-0.9.0/Rakefile b/.gems/gems/faraday-0.9.0/Rakefile new file mode 100644 index 0000000..bcd8c01 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/Rakefile @@ -0,0 +1,71 @@ +require 'date' +require 'fileutils' +require 'openssl' +require 'rake/testtask' +require 'bundler' +Bundler::GemHelper.install_tasks + +task :default => :test + +## helper functions + +def name + @name ||= Dir['*.gemspec'].first.split('.').first +end + +def version + line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/] + line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1] +end + +def gemspec_file + "#{name}.gemspec" +end + +def gem_file + "#{name}-#{version}.gem" +end + +def replace_header(head, header_name) + head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"} +end + +# Adapted from WEBrick::Utils. Skips cert extensions so it +# can be used as a CA bundle +def create_self_signed_cert(bits, cn, comment) + rsa = OpenSSL::PKey::RSA.new(bits) + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 1 + name = OpenSSL::X509::Name.new(cn) + cert.subject = name + cert.issuer = name + cert.not_before = Time.now + cert.not_after = Time.now + (365*24*60*60) + cert.public_key = rsa.public_key + cert.sign(rsa, OpenSSL::Digest::SHA1.new) + return [cert, rsa] +end + +## standard tasks + +desc "Run all tests" +task :test do + exec 'script/test' +end + +desc "Generate certificates for SSL tests" +task :'test:generate_certs' do + cert, key = create_self_signed_cert(1024, [['CN', 'localhost']], 'Faraday Test CA') + FileUtils.mkdir_p 'tmp' + File.open('tmp/faraday-cert.key', 'w') {|f| f.puts(key) } + File.open('tmp/faraday-cert.crt', 'w') {|f| f.puts(cert.to_s) } +end + +file 'tmp/faraday-cert.key' => :'test:generate_certs' +file 'tmp/faraday-cert.crt' => :'test:generate_certs' + +desc "Open an irb session preloaded with this library" +task :console do + sh "irb -rubygems -r ./lib/#{name}.rb" +end diff --git a/.gems/gems/faraday-0.9.0/faraday.gemspec b/.gems/gems/faraday-0.9.0/faraday.gemspec new file mode 100644 index 0000000..3ee9cae --- /dev/null +++ b/.gems/gems/faraday-0.9.0/faraday.gemspec @@ -0,0 +1,34 @@ +lib = "faraday" +lib_file = File.expand_path("../lib/#{lib}.rb", __FILE__) +File.read(lib_file) =~ /\bVERSION\s*=\s*["'](.+?)["']/ +version = $1 + +Gem::Specification.new do |spec| + spec.specification_version = 2 if spec.respond_to? :specification_version= + spec.required_rubygems_version = '>= 1.3.5' + + spec.name = lib + spec.version = version + + spec.summary = "HTTP/REST API client library." + + spec.authors = ["Rick Olson"] + spec.email = 'technoweenie@gmail.com' + spec.homepage = 'https://github.com/lostisland/faraday' + spec.licenses = ['MIT'] + + spec.add_dependency 'multipart-post', '>= 1.2', '< 3' + spec.add_development_dependency 'bundler', '~> 1.0' + + spec.files = %w(.document CHANGELOG.md CONTRIBUTING.md Gemfile LICENSE.md README.md Rakefile) + spec.files << "#{lib}.gemspec" + spec.files += Dir.glob("lib/**/*.rb") + spec.files += Dir.glob("test/**/*.{rb,txt}") + spec.files += Dir.glob("script/*") + + dev_null = File.exist?('/dev/null') ? '/dev/null' : 'NUL' + git_files = `git ls-files -z 2>#{dev_null}` + spec.files &= git_files.split("\0") if $?.success? + + spec.test_files = Dir.glob("test/**/*.rb") +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday.rb b/.gems/gems/faraday-0.9.0/lib/faraday.rb new file mode 100644 index 0000000..4b63ec8 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday.rb @@ -0,0 +1,268 @@ +require 'thread' +require 'cgi' +require 'set' +require 'forwardable' + +# Public: This is the main namespace for Faraday. You can either use it to +# create Faraday::Connection objects, or access it directly. +# +# Examples +# +# Faraday.get "http://faraday.com" +# +# conn = Faraday.new "http://faraday.com" +# conn.get '/' +# +module Faraday + VERSION = "0.9.0" + + class << self + # Public: Gets or sets the root path that Faraday is being loaded from. + # This is the root from where the libraries are auto-loaded from. + attr_accessor :root_path + + # Public: Gets or sets the path that the Faraday libs are loaded from. + attr_accessor :lib_path + + # Public: Gets or sets the Symbol key identifying a default Adapter to use + # for the default Faraday::Connection. + attr_reader :default_adapter + + # Public: Sets the default Faraday::Connection for simple scripts that + # access the Faraday constant directly. + # + # Faraday.get "https://faraday.com" + attr_writer :default_connection + + # Public: Sets the default options used when calling Faraday#new. + attr_writer :default_connection_options + + # Public: Initializes a new Faraday::Connection. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # options - The optional Hash used to configure this Faraday::Connection. + # Any of these values will be set on every request made, unless + # overridden for a specific request. + # :url - String base URL. + # :params - Hash of URI query unencoded key/value pairs. + # :headers - Hash of unencoded HTTP header key/value pairs. + # :request - Hash of request options. + # :ssl - Hash of SSL options. + # :proxy - Hash of Proxy options. + # + # Examples + # + # Faraday.new 'http://faraday.com' + # + # # http://faraday.com?page=1 + # Faraday.new 'http://faraday.com', :params => {:page => 1} + # + # # same + # + # Faraday.new :url => 'http://faraday.com', + # :params => {:page => 1} + # + # Returns a Faraday::Connection. + def new(url = nil, options = nil) + block = block_given? ? Proc.new : nil + options = options ? default_connection_options.merge(options) : default_connection_options.dup + Faraday::Connection.new(url, options, &block) + end + + # Internal: Requires internal Faraday libraries. + # + # *libs - One or more relative String names to Faraday classes. + # + # Returns nothing. + def require_libs(*libs) + libs.each do |lib| + require "#{lib_path}/#{lib}" + end + end + + # Public: Updates default adapter while resetting + # #default_connection. + # + # Returns the new default_adapter. + def default_adapter=(adapter) + @default_connection = nil + @default_adapter = adapter + end + + alias require_lib require_libs + + private + # Internal: Proxies method calls on the Faraday constant to + # #default_connection. + def method_missing(name, *args, &block) + default_connection.send(name, *args, &block) + end + end + + self.root_path = File.expand_path "..", __FILE__ + self.lib_path = File.expand_path "../faraday", __FILE__ + self.default_adapter = :net_http + + # Gets the default connection used for simple scripts. + # + # Returns a Faraday::Connection, configured with the #default_adapter. + def self.default_connection + @default_connection ||= Connection.new + end + + # Gets the default connection options used when calling Faraday#new. + # + # Returns a Faraday::ConnectionOptions. + def self.default_connection_options + @default_connection_options ||= ConnectionOptions.new + end + + if (!defined?(RUBY_ENGINE) || "ruby" == RUBY_ENGINE) && RUBY_VERSION < '1.9' + begin + require 'system_timer' + Timer = SystemTimer + rescue LoadError + warn "Faraday: you may want to install system_timer for reliable timeouts" + end + end + + unless const_defined? :Timer + require 'timeout' + Timer = Timeout + end + + # Public: Adds the ability for other modules to register and lookup + # middleware classes. + module MiddlewareRegistry + # Public: Register middleware class(es) on the current module. + # + # mapping - A Hash mapping Symbol keys to classes. Classes can be expressed + # as fully qualified constant, or a Proc that will be lazily + # called to return the former. + # + # Examples + # + # module Faraday + # class Whatever + # # Middleware looked up by :foo returns Faraday::Whatever::Foo. + # register_middleware :foo => Foo + # + # # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar) + # register_middleware :bar => :Bar + # + # # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz) + # register_middleware :baz => [:Baz, 'baz'] + # end + # end + # + # Returns nothing. + def register_middleware(autoload_path = nil, mapping = nil) + if mapping.nil? + mapping = autoload_path + autoload_path = nil + end + middleware_mutex do + @middleware_autoload_path = autoload_path if autoload_path + (@registered_middleware ||= {}).update(mapping) + end + end + + # Public: Lookup middleware class with a registered Symbol shortcut. + # + # key - The Symbol key for the registered middleware. + # + # Examples + # + # module Faraday + # class Whatever + # register_middleware :foo => Foo + # end + # end + # + # Faraday::Whatever.lookup_middleware(:foo) + # # => Faraday::Whatever::Foo + # + # Returns a middleware Class. + def lookup_middleware(key) + load_middleware(key) || + raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}")) + end + + def middleware_mutex(&block) + @middleware_mutex ||= begin + require 'monitor' + Monitor.new + end + @middleware_mutex.synchronize(&block) + end + + def fetch_middleware(key) + defined?(@registered_middleware) && @registered_middleware[key] + end + + def load_middleware(key) + value = fetch_middleware(key) + case value + when Module + value + when Symbol, String + middleware_mutex do + @registered_middleware[key] = const_get(value) + end + when Proc + middleware_mutex do + @registered_middleware[key] = value.call + end + when Array + middleware_mutex do + const, path = value + if root = @middleware_autoload_path + path = "#{root}/#{path}" + end + require(path) + @registered_middleware[key] = const + end + load_middleware(key) + end + end + end + + def self.const_missing(name) + if name.to_sym == :Builder + warn "Faraday::Builder is now Faraday::RackBuilder." + const_set name, RackBuilder + else + super + end + end + + require_libs "utils", "options", "connection", "rack_builder", "parameters", + "middleware", "adapter", "request", "response", "upload_io", "error" + + if !ENV["FARADAY_NO_AUTOLOAD"] + require_lib 'autoload' + end +end + +# not pulling in active-support JUST for this method. And I love this method. +class Object + # The primary purpose of this method is to "tap into" a method chain, + # in order to perform operations on intermediate results within the chain. + # + # Examples + # + # (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a. + # tap { |x| puts "array: #{x.inspect}" }. + # select { |x| x%2 == 0 }. + # tap { |x| puts "evens: #{x.inspect}" }. + # map { |x| x*x }. + # tap { |x| puts "squares: #{x.inspect}" } + # + # Yields self. + # Returns self. + def tap + yield(self) + self + end unless Object.respond_to?(:tap) +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter.rb new file mode 100644 index 0000000..f018b50 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter.rb @@ -0,0 +1,46 @@ +module Faraday + # Public: This is a base class for all Faraday adapters. Adapters are + # responsible for fulfilling a Faraday request. + class Adapter < Middleware + CONTENT_LENGTH = 'Content-Length'.freeze + + register_middleware File.expand_path('../adapter', __FILE__), + :test => [:Test, 'test'], + :net_http => [:NetHttp, 'net_http'], + :net_http_persistent => [:NetHttpPersistent, 'net_http_persistent'], + :typhoeus => [:Typhoeus, 'typhoeus'], + :patron => [:Patron, 'patron'], + :em_synchrony => [:EMSynchrony, 'em_synchrony'], + :em_http => [:EMHttp, 'em_http'], + :excon => [:Excon, 'excon'], + :rack => [:Rack, 'rack'], + :httpclient => [:HTTPClient, 'httpclient'] + + # Public: This module marks an Adapter as supporting parallel requests. + module Parallelism + attr_writer :supports_parallel + def supports_parallel?() @supports_parallel end + + def inherited(subclass) + super + subclass.supports_parallel = self.supports_parallel? + end + end + + extend Parallelism + self.supports_parallel = false + + def call(env) + env.clear_body if env.needs_body? + end + + def save_response(env, status, body, headers = nil) + env.status = status + env.body = body + env.response_headers = Utils::Headers.new.tap do |response_headers| + response_headers.update headers unless headers.nil? + yield(response_headers) if block_given? + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http.rb new file mode 100644 index 0000000..a248fcf --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http.rb @@ -0,0 +1,237 @@ +module Faraday + class Adapter + # EventMachine adapter is useful for either asynchronous requests + # when in EM reactor loop or for making parallel requests in + # synchronous code. + class EMHttp < Faraday::Adapter + module Options + def connection_config(env) + options = {} + configure_proxy(options, env) + configure_timeout(options, env) + configure_socket(options, env) + configure_ssl(options, env) + options + end + + def request_config(env) + options = { + :body => read_body(env), + :head => env[:request_headers], + # :keepalive => true, + # :file => 'path/to/file', # stream data off disk + } + configure_compression(options, env) + options + end + + def read_body(env) + body = env[:body] + body.respond_to?(:read) ? body.read : body + end + + def configure_proxy(options, env) + if proxy = request_options(env)[:proxy] + options[:proxy] = { + :host => proxy[:uri].host, + :port => proxy[:uri].port, + :authorization => [proxy[:user], proxy[:password]] + } + end + end + + def configure_socket(options, env) + if bind = request_options(env)[:bind] + options[:bind] = { + :host => bind[:host], + :port => bind[:port] + } + end + end + + def configure_ssl(options, env) + if env[:url].scheme == 'https' && env[:ssl] + options[:ssl] = { + :cert_chain_file => env[:ssl][:ca_file], + :verify_peer => env[:ssl].fetch(:verify, true) + } + end + end + + def configure_timeout(options, env) + timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout) + options[:connect_timeout] = options[:inactivity_timeout] = timeout + options[:connect_timeout] = open_timeout if open_timeout + end + + def configure_compression(options, env) + if env[:method] == :get and not options[:head].key? 'accept-encoding' + options[:head]['accept-encoding'] = 'gzip, compressed' + end + end + + def request_options(env) + env[:request] + end + end + + include Options + + dependency 'em-http' + + self.supports_parallel = true + + def self.setup_parallel_manager(options = nil) + Manager.new + end + + def call(env) + super + perform_request env + @app.call env + end + + def perform_request(env) + if parallel?(env) + manager = env[:parallel_manager] + manager.add { + perform_single_request(env). + callback { env[:response].finish(env) } + } + else + unless EventMachine.reactor_running? + error = nil + # start EM, block until request is completed + EventMachine.run do + perform_single_request(env). + callback { EventMachine.stop }. + errback { |client| + error = error_message(client) + EventMachine.stop + } + end + raise_error(error) if error + else + # EM is running: instruct upstream that this is an async request + env[:parallel_manager] = true + perform_single_request(env). + callback { env[:response].finish(env) }. + errback { + # TODO: no way to communicate the error in async mode + raise NotImplementedError + } + end + end + rescue EventMachine::Connectify::CONNECTError => err + if err.message.include?("Proxy Authentication Required") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + + # TODO: reuse the connection to support pipelining + def perform_single_request(env) + req = EventMachine::HttpRequest.new(env[:url], connection_config(env)) + req.setup_request(env[:method], request_config(env)).callback { |client| + save_response(env, client.response_header.status, client.response) do |resp_headers| + client.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + } + end + + def error_message(client) + client.error or "request failed" + end + + def raise_error(msg) + errklass = Faraday::Error::ClientError + if msg == Errno::ETIMEDOUT + errklass = Faraday::Error::TimeoutError + msg = "request timed out" + elsif msg == Errno::ECONNREFUSED + errklass = Faraday::Error::ConnectionFailed + msg = "connection refused" + elsif msg == "connection closed by server" + errklass = Faraday::Error::ConnectionFailed + end + raise errklass, msg + end + + def parallel?(env) + !!env[:parallel_manager] + end + + # The parallel manager is designed to start an EventMachine loop + # and block until all registered requests have been completed. + class Manager + def initialize + reset + end + + def reset + @registered_procs = [] + @num_registered = 0 + @num_succeeded = 0 + @errors = [] + @running = false + end + + def running?() @running end + + def add + if running? + perform_request { yield } + else + @registered_procs << Proc.new + end + @num_registered += 1 + end + + def run + if @num_registered > 0 + @running = true + EventMachine.run do + @registered_procs.each do |proc| + perform_request(&proc) + end + end + if @errors.size > 0 + raise Faraday::Error::ClientError, @errors.first || "connection failed" + end + end + ensure + reset + end + + def perform_request + client = yield + client.callback { @num_succeeded += 1; check_finished } + client.errback { @errors << client.error; check_finished } + end + + def check_finished + if @num_succeeded + @errors.size == @num_registered + EventMachine.stop + end + end + end + end + end +end + +begin + require 'openssl' +rescue LoadError + warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support" +else + require 'faraday/adapter/em_http_ssl_patch' +end if Faraday::Adapter::EMHttp.loaded? diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http_ssl_patch.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http_ssl_patch.rb new file mode 100644 index 0000000..8bbfcbc --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_http_ssl_patch.rb @@ -0,0 +1,56 @@ +require 'openssl' +require 'em-http' + +module EmHttpSslPatch + def ssl_verify_peer(cert_string) + cert = nil + begin + cert = OpenSSL::X509::Certificate.new(cert_string) + rescue OpenSSL::X509::CertificateError + return false + end + + @last_seen_cert = cert + + if certificate_store.verify(@last_seen_cert) + begin + certificate_store.add_cert(@last_seen_cert) + rescue OpenSSL::X509::StoreError => e + raise e unless e.message == 'cert already in hash table' + end + true + else + raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}")) + end + end + + def ssl_handshake_completed + return true unless verify_peer? + + unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host) + raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate)) + else + true + end + end + + def verify_peer? + parent.connopts.tls[:verify_peer] + end + + def host + parent.connopts.host + end + + def certificate_store + @certificate_store ||= begin + store = OpenSSL::X509::Store.new + store.set_default_paths + ca_file = parent.connopts.tls[:cert_chain_file] + store.add_file(ca_file) if ca_file + store + end + end +end + +EventMachine::HttpStubConnection.send(:include, EmHttpSslPatch) diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony.rb new file mode 100644 index 0000000..305e702 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony.rb @@ -0,0 +1,92 @@ +require 'uri' + +module Faraday + class Adapter + class EMSynchrony < Faraday::Adapter + include EMHttp::Options + + dependency do + require 'em-synchrony/em-http' + require 'em-synchrony/em-multi' + require 'fiber' + end + + self.supports_parallel = true + + def self.setup_parallel_manager(options = {}) + ParallelManager.new + end + + def call(env) + super + request = EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env)) + + http_method = env[:method].to_s.downcase.to_sym + + # Queue requests for parallel execution. + if env[:parallel_manager] + env[:parallel_manager].add(request, http_method, request_config(env)) do |resp| + save_response(env, resp.response_header.status, resp.response) do |resp_headers| + resp.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + + # Finalize the response object with values from `env`. + env[:response].finish(env) + end + + # Execute single request. + else + client = nil + block = lambda { request.send(http_method, request_config(env)) } + + if !EM.reactor_running? + EM.run do + Fiber.new { + client = block.call + EM.stop + }.resume + end + else + client = block.call + end + + raise client.error if client.error + + save_response(env, client.response_header.status, client.response) do |resp_headers| + client.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + end + + @app.call env + rescue Errno::ECONNREFUSED + raise Error::ConnectionFailed, $! + rescue EventMachine::Connectify::CONNECTError => err + if err.message.include?("Proxy Authentication Required") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + end + end +end + +require 'faraday/adapter/em_synchrony/parallel_manager' + +begin + require 'openssl' +rescue LoadError + warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support" +else + require 'faraday/adapter/em_http_ssl_patch' +end if Faraday::Adapter::EMSynchrony.loaded? diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony/parallel_manager.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony/parallel_manager.rb new file mode 100644 index 0000000..12a1baf --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/em_synchrony/parallel_manager.rb @@ -0,0 +1,66 @@ +module Faraday + class Adapter + class EMSynchrony < Faraday::Adapter + class ParallelManager + + # Add requests to queue. The `request` argument should be a + # `EM::HttpRequest` object. + def add(request, method, *args, &block) + queue << { + :request => request, + :method => method, + :args => args, + :block => block + } + end + + # Run all requests on queue with `EM::Synchrony::Multi`, wrapping + # it in a reactor and fiber if needed. + def run + result = nil + if !EM.reactor_running? + EM.run { + Fiber.new do + result = perform + EM.stop + end.resume + } + else + result = perform + end + result + end + + + private + + # The request queue. + def queue + @queue ||= [] + end + + # Main `EM::Synchrony::Multi` performer. + def perform + multi = ::EM::Synchrony::Multi.new + + queue.each do |item| + method = "a#{item[:method]}".to_sym + + req = item[:request].send(method, *item[:args]) + req.callback(&item[:block]) + + req_name = "req_#{multi.requests.size}".to_sym + multi.add(req_name, req) + end + + # Clear the queue, so parallel manager objects can be reused. + @queue = [] + + # Block fiber until all requests have returned. + multi.perform + end + + end # ParallelManager + end # EMSynchrony + end # Adapter +end # Faraday diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/excon.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/excon.rb new file mode 100644 index 0000000..db0c7c3 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/excon.rb @@ -0,0 +1,80 @@ +module Faraday + class Adapter + class Excon < Faraday::Adapter + dependency 'excon' + + def initialize(app, connection_options = {}) + @connection_options = connection_options + super(app) + end + + def call(env) + super + + opts = {} + if env[:url].scheme == 'https' && ssl = env[:ssl] + opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true) + opts[:ssl_ca_path] = ssl[:ca_path] if ssl[:ca_path] + opts[:ssl_ca_file] = ssl[:ca_file] if ssl[:ca_file] + opts[:client_cert] = ssl[:client_cert] if ssl[:client_cert] + opts[:client_key] = ssl[:client_key] if ssl[:client_key] + opts[:certificate] = ssl[:certificate] if ssl[:certificate] + opts[:private_key] = ssl[:private_key] if ssl[:private_key] + + # https://github.com/geemus/excon/issues/106 + # https://github.com/jruby/jruby-ossl/issues/19 + opts[:nonblock] = false + end + + if ( req = env[:request] ) + if req[:timeout] + opts[:read_timeout] = req[:timeout] + opts[:connect_timeout] = req[:timeout] + opts[:write_timeout] = req[:timeout] + end + + if req[:open_timeout] + opts[:connect_timeout] = req[:open_timeout] + opts[:write_timeout] = req[:open_timeout] + end + + if req[:proxy] + opts[:proxy] = { + :host => req[:proxy][:uri].host, + :port => req[:proxy][:uri].port, + :scheme => req[:proxy][:uri].scheme, + :user => req[:proxy][:user], + :password => req[:proxy][:password] + } + end + end + + conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options)) + + resp = conn.request \ + :method => env[:method].to_s.upcase, + :headers => env[:request_headers], + :body => read_body(env) + + save_response(env, resp.status.to_i, resp.body, resp.headers) + + @app.call env + rescue ::Excon::Errors::SocketError => err + if err.message =~ /\btimeout\b/ + raise Error::TimeoutError, err + elsif err.message =~ /\bcertificate\b/ + raise Faraday::SSLError, err + else + raise Error::ConnectionFailed, err + end + rescue ::Excon::Errors::Timeout => err + raise Error::TimeoutError, err + end + + # TODO: support streaming requests + def read_body(env) + env[:body].respond_to?(:read) ? env[:body].read : env[:body] + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/httpclient.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/httpclient.rb new file mode 100644 index 0000000..06c663f --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/httpclient.rb @@ -0,0 +1,106 @@ +module Faraday + class Adapter + class HTTPClient < Faraday::Adapter + dependency 'httpclient' + + def client + @client ||= ::HTTPClient.new + end + + def call(env) + super + + if req = env[:request] + if proxy = req[:proxy] + configure_proxy proxy + end + + if bind = req[:bind] + configure_socket bind + end + + configure_timeouts req + end + + if env[:url].scheme == 'https' && ssl = env[:ssl] + configure_ssl ssl + end + + # TODO Don't stream yet. + # https://github.com/nahi/httpclient/pull/90 + env[:body] = env[:body].read if env[:body].respond_to? :read + + resp = client.request env[:method], env[:url], + :body => env[:body], + :header => env[:request_headers] + + save_response env, resp.status, resp.body, resp.headers + + @app.call env + rescue ::HTTPClient::TimeoutError + raise Faraday::Error::TimeoutError, $! + rescue ::HTTPClient::BadResponseError => err + if err.message.include?('status 407') + raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Faraday::Error::ClientError, $! + end + rescue Errno::ECONNREFUSED, EOFError + raise Faraday::Error::ConnectionFailed, $! + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + + def configure_socket(bind) + client.socket_local.host = bind[:host] + client.socket_local.port = bind[:port] + end + + def configure_proxy(proxy) + client.proxy = proxy[:uri] + if proxy[:user] && proxy[:password] + client.set_proxy_auth proxy[:user], proxy[:password] + end + end + + def configure_ssl(ssl) + ssl_config = client.ssl_config + + ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file] + ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path] + ssl_config.cert_store = ssl[:cert_store] if ssl[:cert_store] + ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert] + ssl_config.client_key = ssl[:client_key] if ssl[:client_key] + ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + ssl_config.verify_mode = ssl_verify_mode(ssl) + end + + def configure_timeouts(req) + if req[:timeout] + client.connect_timeout = req[:timeout] + client.receive_timeout = req[:timeout] + client.send_timeout = req[:timeout] + end + + if req[:open_timeout] + client.connect_timeout = req[:open_timeout] + client.send_timeout = req[:open_timeout] + end + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb new file mode 100644 index 0000000..449388a --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb @@ -0,0 +1,124 @@ +begin + require 'net/https' +rescue LoadError + warn "Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support" + require 'net/http' +end +require 'zlib' + +module Faraday + class Adapter + class NetHttp < Faraday::Adapter + NET_HTTP_EXCEPTIONS = [ + EOFError, + Errno::ECONNABORTED, + Errno::ECONNREFUSED, + Errno::ECONNRESET, + Errno::EHOSTUNREACH, + Errno::EINVAL, + Errno::ENETUNREACH, + Net::HTTPBadResponse, + Net::HTTPHeaderSyntaxError, + Net::ProtocolError, + SocketError, + Zlib::GzipFile::Error, + ] + + NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL) + + def call(env) + super + http = net_http_connection(env) + configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl] + + req = env[:request] + http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout] + http.open_timeout = req[:open_timeout] if req[:open_timeout] + + begin + http_response = perform_request(http, env) + rescue *NET_HTTP_EXCEPTIONS => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise Error::ConnectionFailed, err + end + end + + save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers| + http_response.each_header do |key, value| + response_headers[key] = value + end + end + + @app.call env + rescue Timeout::Error => err + raise Faraday::Error::TimeoutError, err + end + + def create_request(env) + request = Net::HTTPGenericRequest.new \ + env[:method].to_s.upcase, # request method + !!env[:body], # is there request body + :head != env[:method], # is there response body + env[:url].request_uri, # request uri path + env[:request_headers] # request headers + + if env[:body].respond_to?(:read) + request.body_stream = env[:body] + else + request.body = env[:body] + end + request + end + + def perform_request(http, env) + if :get == env[:method] and !env[:body] + # prefer `get` to `request` because the former handles gzip (ruby 1.9) + http.get env[:url].request_uri, env[:request_headers] + else + http.request create_request(env) + end + end + + def net_http_connection(env) + if proxy = env[:request][:proxy] + Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password]) + else + Net::HTTP + end.new(env[:url].host, env[:url].port) + end + + def configure_ssl(http, ssl) + http.use_ssl = true + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.cert = ssl[:client_cert] if ssl[:client_cert] + http.key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ca_path = ssl[:ca_path] if ssl[:ca_path] + http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + http.ssl_version = ssl[:version] if ssl[:version] + end + + def ssl_cert_store(ssl) + return ssl[:cert_store] if ssl[:cert_store] + # Use the default cert store by default, i.e. system ca certs + cert_store = OpenSSL::X509::Store.new + cert_store.set_default_paths + cert_store + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http_persistent.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http_persistent.rb new file mode 100644 index 0000000..e0cc958 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http_persistent.rb @@ -0,0 +1,47 @@ +# Rely on autoloading instead of explicit require; helps avoid the "already +# initialized constant" warning on Ruby 1.8.7 when NetHttp is refereced below. +# require 'faraday/adapter/net_http' + +module Faraday + class Adapter + # Experimental adapter for net-http-persistent + class NetHttpPersistent < NetHttp + dependency 'net/http/persistent' + + def net_http_connection(env) + if proxy = env[:request][:proxy] + proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s) + proxy_uri.user = proxy_uri.password = nil + # awful patch for net-http-persistent 2.8 not unescaping user/password + (class << proxy_uri; self; end).class_eval do + define_method(:user) { proxy[:user] } + define_method(:password) { proxy[:password] } + end if proxy[:user] + end + Net::HTTP::Persistent.new 'Faraday', proxy_uri + end + + def perform_request(http, env) + http.request env[:url], create_request(env) + rescue Net::HTTP::Persistent::Error => error + if error.message.include? 'Timeout' + raise Faraday::Error::TimeoutError, error + elsif error.message.include? 'connection refused' + raise Faraday::Error::ConnectionFailed, error + else + raise + end + end + + def configure_ssl(http, ssl) + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.certificate = ssl[:client_cert] if ssl[:client_cert] + http.private_key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ssl_version = ssl[:version] if ssl[:version] + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/patron.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/patron.rb new file mode 100644 index 0000000..24a6d83 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/patron.rb @@ -0,0 +1,68 @@ +module Faraday + class Adapter + class Patron < Faraday::Adapter + dependency 'patron' + + def initialize(app, &block) + super(app) + @block = block + end + + def call(env) + super + + # TODO: support streaming requests + env[:body] = env[:body].read if env[:body].respond_to? :read + + session = @session ||= create_session + + if req = env[:request] + session.timeout = session.connect_timeout = req[:timeout] if req[:timeout] + session.connect_timeout = req[:open_timeout] if req[:open_timeout] + + if proxy = req[:proxy] + proxy_uri = proxy[:uri].dup + proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20') + proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20') + session.proxy = proxy_uri.to_s + end + end + + response = begin + data = env[:body] ? env[:body].to_s : nil + session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data) + rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed + raise Error::ConnectionFailed, $! + end + + save_response(env, response.status, response.body, response.headers) + + @app.call env + rescue ::Patron::TimeoutError => err + raise Faraday::Error::TimeoutError, err + rescue ::Patron::Error => err + if err.message.include?("code 407") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + end + + if loaded? && defined?(::Patron::Request::VALID_ACTIONS) + # HAX: helps but doesn't work completely + # https://github.com/toland/patron/issues/34 + ::Patron::Request::VALID_ACTIONS.tap do |actions| + actions << :patch unless actions.include? :patch + actions << :options unless actions.include? :options + end + end + + def create_session + session = ::Patron::Session.new + session.insecure = true + @block.call(session) if @block + session + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/rack.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/rack.rb new file mode 100644 index 0000000..0d21464 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/rack.rb @@ -0,0 +1,58 @@ +module Faraday + class Adapter + # Sends requests to a Rack app. + # + # Examples + # + # class MyRackApp + # def call(env) + # [200, {'Content-Type' => 'text/html'}, ["hello world"]] + # end + # end + # + # Faraday.new do |conn| + # conn.adapter :rack, MyRackApp.new + # end + class Rack < Faraday::Adapter + dependency 'rack/test' + + # not prefixed with "HTTP_" + SPECIAL_HEADERS = %w[ CONTENT_LENGTH CONTENT_TYPE ] + + def initialize(faraday_app, rack_app) + super(faraday_app) + mock_session = ::Rack::MockSession.new(rack_app) + @session = ::Rack::Test::Session.new(mock_session) + end + + def call(env) + super + rack_env = { + :method => env[:method], + :input => env[:body].respond_to?(:read) ? env[:body].read : env[:body], + 'rack.url_scheme' => env[:url].scheme + } + + env[:request_headers].each do |name, value| + name = name.upcase.tr('-', '_') + name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name + rack_env[name] = value + end if env[:request_headers] + + timeout = env[:request][:timeout] || env[:request][:open_timeout] + response = if timeout + Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) } + else + execute_request(env, rack_env) + end + + save_response(env, response.status, response.body, response.headers) + @app.call env + end + + def execute_request(env, rack_env) + @session.request(env[:url].to_s, rack_env) + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/test.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/test.rb new file mode 100644 index 0000000..9a34575 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/test.rb @@ -0,0 +1,162 @@ +module Faraday + class Adapter + # test = Faraday::Connection.new do + # use Faraday::Adapter::Test do |stub| + # stub.get '/nigiri/sake.json' do + # [200, {}, 'hi world'] + # end + # end + # end + # + # resp = test.get '/nigiri/sake.json' + # resp.body # => 'hi world' + # + class Test < Faraday::Adapter + attr_accessor :stubs + + class Stubs + class NotFound < StandardError + end + + def initialize + # {:get => [Stub, Stub]} + @stack, @consumed = {}, {} + yield(self) if block_given? + end + + def empty? + @stack.empty? + end + + def match(request_method, path, headers, body) + return false if !@stack.key?(request_method) + stack = @stack[request_method] + consumed = (@consumed[request_method] ||= []) + + if stub = matches?(stack, path, headers, body) + consumed << stack.delete(stub) + stub + else + matches?(consumed, path, headers, body) + end + end + + def get(path, headers = {}, &block) + new_stub(:get, path, headers, &block) + end + + def head(path, headers = {}, &block) + new_stub(:head, path, headers, &block) + end + + def post(path, body=nil, headers = {}, &block) + new_stub(:post, path, headers, body, &block) + end + + def put(path, body=nil, headers = {}, &block) + new_stub(:put, path, headers, body, &block) + end + + def patch(path, body=nil, headers = {}, &block) + new_stub(:patch, path, headers, body, &block) + end + + def delete(path, headers = {}, &block) + new_stub(:delete, path, headers, &block) + end + + def options(path, headers = {}, &block) + new_stub(:options, path, headers, &block) + end + + # Raises an error if any of the stubbed calls have not been made. + def verify_stubbed_calls + failed_stubs = [] + @stack.each do |method, stubs| + unless stubs.size == 0 + failed_stubs.concat(stubs.map {|stub| + "Expected #{method} #{stub}." + }) + end + end + raise failed_stubs.join(" ") unless failed_stubs.size == 0 + end + + protected + + def new_stub(request_method, path, headers = {}, body=nil, &block) + normalized_path = Faraday::Utils.normalize_path(path) + (@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block) + end + + def matches?(stack, path, headers, body) + stack.detect { |stub| stub.matches?(path, headers, body) } + end + end + + class Stub < Struct.new(:path, :params, :headers, :body, :block) + def initialize(full, headers, body, block) + path, query = full.split('?') + params = query ? + Faraday::Utils.parse_nested_query(query) : + {} + super(path, params, headers, body, block) + end + + def matches?(request_uri, request_headers, request_body) + request_path, request_query = request_uri.split('?') + request_params = request_query ? + Faraday::Utils.parse_nested_query(request_query) : + {} + request_path == path && + params_match?(request_params) && + (body.to_s.size.zero? || request_body == body) && + headers_match?(request_headers) + end + + def params_match?(request_params) + params.keys.all? do |key| + request_params[key] == params[key] + end + end + + def headers_match?(request_headers) + headers.keys.all? do |key| + request_headers[key] == headers[key] + end + end + + def to_s + "#{path} #{body}" + end + end + + def initialize(app, stubs=nil, &block) + super(app) + @stubs = stubs || Stubs.new + configure(&block) if block + end + + def configure + yield(stubs) + end + + def call(env) + super + normalized_path = Faraday::Utils.normalize_path(env[:url]) + params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder + + if stub = stubs.match(env[:method], normalized_path, env.request_headers, env[:body]) + env[:params] = (query = env[:url].query) ? + params_encoder.decode(query) : + {} + status, headers, body = stub.block.call(env) + save_response(env, status, body, headers) + else + raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}" + end + @app.call(env) + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/adapter/typhoeus.rb b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/typhoeus.rb new file mode 100644 index 0000000..69b6a51 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/adapter/typhoeus.rb @@ -0,0 +1,123 @@ +module Faraday + class Adapter + class Typhoeus < Faraday::Adapter + self.supports_parallel = true + + def self.setup_parallel_manager(options = {}) + options.empty? ? ::Typhoeus::Hydra.hydra : ::Typhoeus::Hydra.new(options) + end + + dependency 'typhoeus' + + def call(env) + super + perform_request env + @app.call env + end + + def perform_request(env) + read_body env + + hydra = env[:parallel_manager] || self.class.setup_parallel_manager + hydra.queue request(env) + hydra.run unless parallel?(env) + rescue Errno::ECONNREFUSED + raise Error::ConnectionFailed, $! + end + + # TODO: support streaming requests + def read_body(env) + env[:body] = env[:body].read if env[:body].respond_to? :read + end + + def request(env) + method = env[:method] + # For some reason, prevents Typhoeus from using "100-continue". + # We want this because Webrick 1.3.1 can't seem to handle it w/ PUT. + method = method.to_s.upcase if method == :put + + req = ::Typhoeus::Request.new env[:url].to_s, + :method => method, + :body => env[:body], + :headers => env[:request_headers], + :disable_ssl_peer_verification => (env[:ssl] && env[:ssl].disable?) + + configure_ssl req, env + configure_proxy req, env + configure_timeout req, env + configure_socket req, env + + req.on_complete do |resp| + if resp.timed_out? + if parallel?(env) + # TODO: error callback in async mode + else + raise Faraday::Error::TimeoutError, "request timed out" + end + end + + case resp.curl_return_code + when 0 + # everything OK + when 7 + raise Error::ConnectionFailed, resp.curl_error_message + when 60 + raise Faraday::SSLError, resp.curl_error_message + else + raise Error::ClientError, resp.curl_error_message + end + + save_response(env, resp.code, resp.body) do |response_headers| + response_headers.parse resp.headers + end + # in async mode, :response is initialized at this point + env[:response].finish(env) if parallel?(env) + end + + req + end + + def configure_ssl(req, env) + ssl = env[:ssl] + + req.ssl_version = ssl[:version] if ssl[:version] + req.ssl_cert = ssl[:client_cert] if ssl[:client_cert] + req.ssl_key = ssl[:client_key] if ssl[:client_key] + req.ssl_cacert = ssl[:ca_file] if ssl[:ca_file] + req.ssl_capath = ssl[:ca_path] if ssl[:ca_path] + end + + def configure_proxy(req, env) + proxy = request_options(env)[:proxy] + return unless proxy + + req.proxy = "#{proxy[:uri].host}:#{proxy[:uri].port}" + + if proxy[:user] && proxy[:password] + req.proxy_username = proxy[:user] + req.proxy_password = proxy[:password] + end + end + + def configure_timeout(req, env) + env_req = request_options(env) + req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout] + req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout] + end + + def configure_socket(req, env) + if bind = request_options(env)[:bind] + req.interface = bind[:host] + end + end + + def request_options(env) + env[:request] + end + + def parallel?(env) + !!env[:parallel_manager] + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/autoload.rb b/.gems/gems/faraday-0.9.0/lib/faraday/autoload.rb new file mode 100644 index 0000000..ec413ff --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/autoload.rb @@ -0,0 +1,85 @@ +module Faraday + # Internal: Adds the ability for other modules to manage autoloadable + # constants. + module AutoloadHelper + # Internal: Registers the constants to be auto loaded. + # + # prefix - The String require prefix. If the path is inside Faraday, then + # it will be prefixed with the root path of this loaded Faraday + # version. + # options - Hash of Symbol => String library names. + # + # Examples. + # + # Faraday.autoload_all 'faraday/foo', + # :Bar => 'bar' + # + # # requires faraday/foo/bar to load Faraday::Bar. + # Faraday::Bar + # + # + # Returns nothing. + def autoload_all(prefix, options) + if prefix =~ /^faraday(\/|$)/i + prefix = File.join(Faraday.root_path, prefix) + end + options.each do |const_name, path| + autoload const_name, File.join(prefix, path) + end + end + + # Internal: Loads each autoloaded constant. If thread safety is a concern, + # wrap this in a Mutex. + # + # Returns nothing. + def load_autoloaded_constants + constants.each do |const| + const_get(const) if autoload?(const) + end + end + + # Internal: Filters the module's contents with those that have been already + # autoloaded. + # + # Returns an Array of Class/Module objects. + def all_loaded_constants + constants.map { |c| const_get(c) }. + select { |a| a.respond_to?(:loaded?) && a.loaded? } + end + end + + class Adapter + extend AutoloadHelper + autoload_all 'faraday/adapter', + :NetHttp => 'net_http', + :NetHttpPersistent => 'net_http_persistent', + :Typhoeus => 'typhoeus', + :EMSynchrony => 'em_synchrony', + :EMHttp => 'em_http', + :Patron => 'patron', + :Excon => 'excon', + :Test => 'test', + :Rack => 'rack', + :HTTPClient => 'httpclient' + end + + class Request + extend AutoloadHelper + autoload_all 'faraday/request', + :UrlEncoded => 'url_encoded', + :Multipart => 'multipart', + :Retry => 'retry', + :Timeout => 'timeout', + :Authorization => 'authorization', + :BasicAuthentication => 'basic_authentication', + :TokenAuthentication => 'token_authentication', + :Instrumentation => 'instrumentation' + end + + class Response + extend AutoloadHelper + autoload_all 'faraday/response', + :RaiseError => 'raise_error', + :Logger => 'logger' + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/connection.rb b/.gems/gems/faraday-0.9.0/lib/faraday/connection.rb new file mode 100644 index 0000000..1e408e2 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/connection.rb @@ -0,0 +1,432 @@ +module Faraday + # Public: Connection objects manage the default properties and the middleware + # stack for fulfilling an HTTP request. + # + # Examples + # + # conn = Faraday::Connection.new 'http://sushi.com' + # + # # GET http://sushi.com/nigiri + # conn.get 'nigiri' + # # => # + # + class Connection + # A Set of allowed HTTP verbs. + METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options] + + # Public: Returns a Hash of URI query unencoded key/value pairs. + attr_reader :params + + # Public: Returns a Hash of unencoded HTTP header key/value pairs. + attr_reader :headers + + # Public: Returns a URI with the prefix used for all requests from this + # Connection. This includes a default host name, scheme, port, and path. + attr_reader :url_prefix + + # Public: Returns the Faraday::Builder for this Connection. + attr_reader :builder + + # Public: Returns a Hash of the request options. + attr_reader :options + + # Public: Returns a Hash of the SSL options. + attr_reader :ssl + + # Public: Returns the parallel manager for this Connection. + attr_reader :parallel_manager + + # Public: Sets the default parallel manager for this connection. + attr_writer :default_parallel_manager + + # Public: Initializes a new Faraday::Connection. + # + # url - URI or String base URL to use as a prefix for all + # requests (optional). + # options - Hash or Faraday::ConnectionOptions. + # :url - URI or String base URL (default: "http:/"). + # :params - Hash of URI query unencoded key/value pairs. + # :headers - Hash of unencoded HTTP header key/value pairs. + # :request - Hash of request options. + # :ssl - Hash of SSL options. + # :proxy - URI, String or Hash of HTTP proxy options + # (default: "http_proxy" environment variable). + # :uri - URI or String + # :user - String (optional) + # :password - String (optional) + def initialize(url = nil, options = nil) + if url.is_a?(Hash) + options = ConnectionOptions.from(url) + url = options.url + else + options = ConnectionOptions.from(options) + end + + @parallel_manager = nil + @headers = Utils::Headers.new + @params = Utils::ParamsHash.new + @options = options.request + @ssl = options.ssl + @default_parallel_manager = options.parallel_manager + + @builder = options.builder || begin + # pass an empty block to Builder so it doesn't assume default middleware + options.new_builder(block_given? ? Proc.new { |b| } : nil) + end + + self.url_prefix = url || 'http:/' + + @params.update(options.params) if options.params + @headers.update(options.headers) if options.headers + + @proxy = nil + proxy(options.fetch(:proxy) { + uri = ENV['http_proxy'] + if uri && !uri.empty? + uri = 'http://' + uri if uri !~ /^http/i + uri + end + }) + + yield(self) if block_given? + + @headers[:user_agent] ||= "Faraday v#{VERSION}" + end + + # Public: Sets the Hash of URI query unencoded key/value pairs. + def params=(hash) + @params.replace hash + end + + # Public: Sets the Hash of unencoded HTTP header key/value pairs. + def headers=(hash) + @headers.replace hash + end + + extend Forwardable + + def_delegators :builder, :build, :use, :request, :response, :adapter, :app + + # Public: Makes an HTTP request without a body. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # params - Hash of URI query unencoded key/value pairs. + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Examples + # + # conn.get '/items', {:page => 1}, :accept => 'application/json' + # conn.head '/items/1' + # + # # ElasticSearch example sending a body with GET. + # conn.get '/twitter/tweet/_search' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(:query => {...}) + # end + # + # Yields a Faraday::Response for further request customizations. + # Returns a Faraday::Response. + # + # Signature + # + # (url = nil, params = nil, headers = nil) + # + # verb - An HTTP verb: get, head, or delete. + %w[get head delete].each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, params = nil, headers = nil) + run_request(:#{method}, url, nil, headers) { |request| + request.params.update(params) if params + yield(request) if block_given? + } + end + RUBY + end + + # Public: Makes an HTTP request with a body. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # body - The String body for the request. + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Examples + # + # conn.post '/items', data, :content_type => 'application/json' + # + # # Simple ElasticSearch indexing sample. + # conn.post '/twitter/tweet' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(:user => 'kimchy', ...) + # end + # + # Yields a Faraday::Response for further request customizations. + # Returns a Faraday::Response. + # + # Signature + # + # (url = nil, body = nil, headers = nil) + # + # verb - An HTTP verb: post, put, or patch. + %w[post put patch].each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, body = nil, headers = nil, &block) + run_request(:#{method}, url, body, headers, &block) + end + RUBY + end + + # Public: Sets up the Authorization header with these credentials, encoded + # with base64. + # + # login - The authentication login. + # pass - The authentication password. + # + # Examples + # + # conn.basic_auth 'Aladdin', 'open sesame' + # conn.headers['Authorization'] + # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" + # + # Returns nothing. + def basic_auth(login, pass) + set_authorization_header(:basic_auth, login, pass) + end + + # Public: Sets up the Authorization header with the given token. + # + # token - The String token. + # options - Optional Hash of extra token options. + # + # Examples + # + # conn.token_auth 'abcdef', :foo => 'bar' + # conn.headers['Authorization'] + # # => "Token token=\"abcdef\", + # foo=\"bar\"" + # + # Returns nothing. + def token_auth(token, options = nil) + set_authorization_header(:token_auth, token, options) + end + + # Public: Sets up a custom Authorization header. + # + # type - The String authorization type. + # token - The String or Hash token. A String value is taken literally, and + # a Hash is encoded into comma separated key/value pairs. + # + # Examples + # + # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM' + # conn.headers['Authorization'] + # # => "Bearer mF_9.B5f-4.1JqM" + # + # conn.authorization :Token, :token => 'abcdef', :foo => 'bar' + # conn.headers['Authorization'] + # # => "Token token=\"abcdef\", + # foo=\"bar\"" + # + # Returns nothing. + def authorization(type, token) + set_authorization_header(:authorization, type, token) + end + + # Internal: Traverse the middleware stack in search of a + # parallel-capable adapter. + # + # Yields in case of not found. + # + # Returns a parallel manager or nil if not found. + def default_parallel_manager + @default_parallel_manager ||= begin + handler = @builder.handlers.detect do |h| + h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel? + end + + if handler + handler.klass.setup_parallel_manager + elsif block_given? + yield + end + end + end + + # Public: Determine if this Faraday::Connection can make parallel requests. + # + # Returns true or false. + def in_parallel? + !!@parallel_manager + end + + # Public: Sets up the parallel manager to make a set of requests. + # + # manager - The parallel manager that this Connection's Adapter uses. + # + # Yields a block to execute multiple requests. + # Returns nothing. + def in_parallel(manager = nil) + @parallel_manager = manager || default_parallel_manager { + warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack" + warn caller[2,10].join("\n") + nil + } + yield + @parallel_manager && @parallel_manager.run + ensure + @parallel_manager = nil + end + + # Public: Gets or Sets the Hash proxy options. + def proxy(arg = nil) + return @proxy if arg.nil? + @proxy = ProxyOptions.from(arg) + end + + def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port= + def_delegator :url_prefix, :path, :path_prefix + + # Public: Parses the giving url with URI and stores the individual + # components in this connection. These components serve as defaults for + # requests made by this connection. + # + # url - A String or URI. + # + # Examples + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://sushi.com/api" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri + # + # Returns the parsed URI from teh given input.. + def url_prefix=(url, encoder = nil) + uri = @url_prefix = Utils.URI(url) + self.path_prefix = uri.path + + params.merge_query(uri.query, encoder) + uri.query = nil + + with_uri_credentials(uri) do |user, password| + basic_auth user, password + uri.user = uri.password = nil + end + + uri + end + + # Public: Sets the path prefix and ensures that it always has a leading + # slash. + # + # value - A String. + # + # Returns the new String path prefix. + def path_prefix=(value) + url_prefix.path = if value + value = '/' + value unless value[0,1] == '/' + value + end + end + + # Public: Takes a relative url for a request and combines it with the defaults + # set on the connection instance. + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://sushi.com/api?token=abc" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2 + # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2 + # + def build_url(url = nil, extra_params = nil) + uri = build_exclusive_url(url) + + query_values = params.dup.merge_query(uri.query, options.params_encoder) + query_values.update extra_params if extra_params + uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder) + + uri + end + + # Builds and runs the Faraday::Request. + # + # method - The Symbol HTTP method. + # url - The String or URI to access. + # body - The String body + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Returns a Faraday::Response. + def run_request(method, url, body, headers) + if !METHODS.include?(method) + raise ArgumentError, "unknown http method: #{method}" + end + + request = build_request(method) do |req| + req.url(url) if url + req.headers.update(headers) if headers + req.body = body if body + yield(req) if block_given? + end + + builder.build_response(self, request) + end + + # Creates and configures the request object. + # + # Returns the new Request. + def build_request(method) + Request.create(method) do |req| + req.params = self.params.dup + req.headers = self.headers.dup + req.options = self.options.merge(:proxy => self.proxy) + yield(req) if block_given? + end + end + + # Internal: Build an absolute URL based on url_prefix. + # + # url - A String or URI-like object + # params - A Faraday::Utils::ParamsHash to replace the query values + # of the resulting url (default: nil). + # + # Returns the resulting URI instance. + def build_exclusive_url(url = nil, params = nil) + url = nil if url.respond_to?(:empty?) and url.empty? + base = url_prefix + if url and base.path and base.path !~ /\/$/ + base = base.dup + base.path = base.path + '/' # ensure trailing slash + end + uri = url ? base + url : base + uri.query = params.to_query(options.params_encoder) if params + uri.query = nil if uri.query and uri.query.empty? + uri + end + + # Internal: Creates a duplicate of this Faraday::Connection. + # + # Returns a Faraday::Connection. + def dup + self.class.new(build_exclusive_url, :headers => headers.dup, :params => params.dup, :builder => builder.dup, :ssl => ssl.dup) + end + + # Internal: Yields username and password extracted from a URI if they both exist. + def with_uri_credentials(uri) + if uri.user and uri.password + yield(Utils.unescape(uri.user), Utils.unescape(uri.password)) + end + end + + def set_authorization_header(header_type, *args) + header = Faraday::Request.lookup_middleware(header_type). + header(*args) + headers[Faraday::Request::Authorization::KEY] = header + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/error.rb b/.gems/gems/faraday-0.9.0/lib/faraday/error.rb new file mode 100644 index 0000000..1771230 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/error.rb @@ -0,0 +1,53 @@ +module Faraday + class Error < StandardError; end + class MissingDependency < Error; end + + class ClientError < Error + attr_reader :response + + def initialize(ex, response = nil) + @wrapped_exception = nil + @response = response + + if ex.respond_to?(:backtrace) + super(ex.message) + @wrapped_exception = ex + elsif ex.respond_to?(:each_key) + super("the server responded with status #{ex[:status]}") + @response = ex + else + super(ex.to_s) + end + end + + def backtrace + if @wrapped_exception + @wrapped_exception.backtrace + else + super + end + end + + def inspect + %(#<#{self.class}>) + end + end + + class ConnectionFailed < ClientError; end + class ResourceNotFound < ClientError; end + class ParsingError < ClientError; end + + class TimeoutError < ClientError + def initialize(ex = nil) + super(ex || "timeout") + end + end + + class SSLError < ClientError + end + + [:MissingDependency, :ClientError, :ConnectionFailed, :ResourceNotFound, + :ParsingError, :TimeoutError, :SSLError].each do |const| + Error.const_set(const, Faraday.const_get(const)) + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/middleware.rb b/.gems/gems/faraday-0.9.0/lib/faraday/middleware.rb new file mode 100644 index 0000000..c45d51a --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/middleware.rb @@ -0,0 +1,37 @@ +module Faraday + class Middleware + extend MiddlewareRegistry + + class << self + attr_accessor :load_error + private :load_error= + end + + self.load_error = nil + + # Executes a block which should try to require and reference dependent libraries + def self.dependency(lib = nil) + lib ? require(lib) : yield + rescue LoadError, NameError => error + self.load_error = error + end + + def self.new(*) + raise "missing dependency for #{self}: #{load_error.message}" unless loaded? + super + end + + def self.loaded? + load_error.nil? + end + + def self.inherited(subclass) + super + subclass.send(:load_error=, self.load_error) + end + + def initialize(app = nil) + @app = app + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/options.rb b/.gems/gems/faraday-0.9.0/lib/faraday/options.rb new file mode 100644 index 0000000..c1b36f6 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/options.rb @@ -0,0 +1,350 @@ +module Faraday + # Subclasses Struct with some special helpers for converting from a Hash to + # a Struct. + class Options < Struct + # Public + def self.from(value) + value ? new.update(value) : new + end + + # Public + def each + return to_enum(:each) unless block_given? + members.each do |key| + yield(key.to_sym, send(key)) + end + end + + # Public + def update(obj) + obj.each do |key, value| + if sub_options = self.class.options_for(key) + value = sub_options.from(value) if value + elsif Hash === value + hash = {} + value.each do |hash_key, hash_value| + hash[hash_key] = hash_value + end + value = hash + end + + self.send("#{key}=", value) unless value.nil? + end + self + end + + alias merge! update + + # Public + def delete(key) + value = send(key) + send("#{key}=", nil) + value + end + + # Public + def clear + members.each { |member| delete(member) } + end + + # Public + def merge(value) + dup.update(value) + end + + # Public + def fetch(key, *args) + unless symbolized_key_set.include?(key.to_sym) + key_setter = "#{key}=" + if args.size > 0 + send(key_setter, args.first) + elsif block_given? + send(key_setter, Proc.new.call(key)) + else + raise self.class.fetch_error_class, "key not found: #{key.inspect}" + end + end + send(key) + end + + # Public + def values_at(*keys) + keys.map { |key| send(key) } + end + + # Public + def keys + members.reject { |member| send(member).nil? } + end + + # Public + def empty? + keys.empty? + end + + # Public + def each_key + return to_enum(:each_key) unless block_given? + keys.each do |key| + yield(key) + end + end + + # Public + def key?(key) + keys.include?(key) + end + + alias has_key? key? + + # Public + def each_value + return to_enum(:each_value) unless block_given? + values.each do |value| + yield(value) + end + end + + # Public + def value?(value) + values.include?(value) + end + + alias has_value? value? + + # Public + def to_hash + hash = {} + members.each do |key| + value = send(key) + hash[key.to_sym] = value unless value.nil? + end + hash + end + + # Internal + def inspect + values = [] + members.each do |member| + value = send(member) + values << "#{member}=#{value.inspect}" if value + end + values = values.empty? ? ' (empty)' : (' ' << values.join(", ")) + + %(#<#{self.class}#{values}>) + end + + # Internal + def self.options(mapping) + attribute_options.update(mapping) + end + + # Internal + def self.options_for(key) + attribute_options[key] + end + + # Internal + def self.attribute_options + @attribute_options ||= {} + end + + def self.memoized(key) + memoized_attributes[key.to_sym] = Proc.new + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{key}() self[:#{key}]; end + RUBY + end + + def self.memoized_attributes + @memoized_attributes ||= {} + end + + def [](key) + key = key.to_sym + if method = self.class.memoized_attributes[key] + super(key) || (self[key] = instance_eval(&method)) + else + super + end + end + + def symbolized_key_set + @symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym }) + end + + def self.inherited(subclass) + super + subclass.attribute_options.update(attribute_options) + subclass.memoized_attributes.update(memoized_attributes) + end + + def self.fetch_error_class + @fetch_error_class ||= if Object.const_defined?(:KeyError) + ::KeyError + else + ::IndexError + end + end + end + + class RequestOptions < Options.new(:params_encoder, :proxy, :bind, + :timeout, :open_timeout, :boundary, + :oauth) + + def []=(key, value) + if key && key.to_sym == :proxy + super(key, value ? ProxyOptions.from(value) : nil) + else + super(key, value) + end + end + end + + class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode, + :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, :version) + + def verify? + verify != false + end + + def disable? + !verify? + end + end + + class ProxyOptions < Options.new(:uri, :user, :password) + extend Forwardable + def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path= + + def self.from(value) + case value + when String + value = {:uri => Utils.URI(value)} + when URI + value = {:uri => value} + when Hash, Options + if uri = value.delete(:uri) + value[:uri] = Utils.URI(uri) + end + end + super(value) + end + + memoized(:user) { uri.user && Utils.unescape(uri.user) } + memoized(:password) { uri.password && Utils.unescape(uri.password) } + end + + class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url, + :parallel_manager, :params, :headers, :builder_class) + + options :request => RequestOptions, :ssl => SSLOptions + + memoized(:request) { self.class.options_for(:request).new } + + memoized(:ssl) { self.class.options_for(:ssl).new } + + memoized(:builder_class) { RackBuilder } + + def new_builder(block) + builder_class.new(&block) + end + end + + class Env < Options.new(:method, :body, :url, :request, :request_headers, + :ssl, :parallel_manager, :params, :response, :response_headers, :status) + + ContentLength = 'Content-Length'.freeze + StatusesWithoutBody = Set.new [204, 304] + SuccessfulStatuses = 200..299 + + # A Set of HTTP verbs that typically send a body. If no body is set for + # these requests, the Content-Length header is set to 0. + MethodsWithBodies = Set.new [:post, :put, :patch, :options] + + options :request => RequestOptions, + :request_headers => Utils::Headers, :response_headers => Utils::Headers + + extend Forwardable + + def_delegators :request, :params_encoder + + # Public + def [](key) + if in_member_set?(key) + super(key) + else + custom_members[key] + end + end + + # Public + def []=(key, value) + if in_member_set?(key) + super(key, value) + else + custom_members[key] = value + end + end + + # Public + def success? + SuccessfulStatuses.include?(status) + end + + # Public + def needs_body? + !body && MethodsWithBodies.include?(method) + end + + # Public + def clear_body + request_headers[ContentLength] = '0' + self.body = '' + end + + # Public + def parse_body? + !StatusesWithoutBody.include?(status) + end + + # Public + def parallel? + !!parallel_manager + end + + def inspect + attrs = [nil] + members.each do |mem| + if value = send(mem) + attrs << "@#{mem}=#{value.inspect}" + end + end + if !custom_members.empty? + attrs << "@custom=#{custom_members.inspect}" + end + %(#<#{self.class}#{attrs.join(" ")}>) + end + + # Internal + def custom_members + @custom_members ||= {} + end + + # Internal + if members.first.is_a?(Symbol) + def in_member_set?(key) + self.class.member_set.include?(key.to_sym) + end + else + def in_member_set?(key) + self.class.member_set.include?(key.to_s) + end + end + + # Internal + def self.member_set + @member_set ||= Set.new(members) + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/parameters.rb b/.gems/gems/faraday-0.9.0/lib/faraday/parameters.rb new file mode 100644 index 0000000..136c43b --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/parameters.rb @@ -0,0 +1,193 @@ +module Faraday + module NestedParamsEncoder + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def self.escape(s) + return s.to_s.gsub(ESCAPE_RE) { + '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def self.unescape(s) + CGI.unescape(s.to_s) + end + + def self.encode(params) + return nil if params == nil + + if !params.is_a?(Array) + if !params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! + end + + # Helper lambda + to_query = lambda do |parent, value| + if value.is_a?(Hash) + value = value.map do |key, val| + key = escape(key) + [key, val] + end + value.sort! + buffer = "" + value.each do |key, val| + new_parent = "#{parent}%5B#{key}%5D" + buffer << "#{to_query.call(new_parent, val)}&" + end + return buffer.chop + elsif value.is_a?(Array) + buffer = "" + value.each_with_index do |val, i| + new_parent = "#{parent}%5B%5D" + buffer << "#{to_query.call(new_parent, val)}&" + end + return buffer.chop + else + encoded_value = escape(value) + return "#{parent}=#{encoded_value}" + end + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = '' + params.each do |parent, value| + encoded_parent = escape(parent) + buffer << "#{to_query.call(encoded_parent, value)}&" + end + return buffer.chop + end + + def self.decode(query) + return nil if query == nil + # Recursive helper lambda + dehash = lambda do |hash| + hash.each do |(key, value)| + if value.kind_of?(Hash) + hash[key] = dehash.call(value) + end + end + # Numeric keys implies an array + if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ } + hash.sort.inject([]) do |accu, (_, value)| + accu << value; accu + end + else + hash + end + end + + empty_accumulator = {} + return ((query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact.inject(empty_accumulator.dup) do |accu, (key, value)| + key = unescape(key) + if value.kind_of?(String) + value = unescape(value.gsub(/\+/, ' ')) + end + + array_notation = !!(key =~ /\[\]$/) + subkeys = key.split(/[\[\]]+/) + current_hash = accu + for i in 0...(subkeys.size - 1) + subkey = subkeys[i] + current_hash[subkey] = {} unless current_hash[subkey] + current_hash = current_hash[subkey] + end + if array_notation + current_hash[subkeys.last] = [] unless current_hash[subkeys.last] + current_hash[subkeys.last] << value + else + current_hash[subkeys.last] = value + end + accu + end).inject(empty_accumulator.dup) do |accu, (key, value)| + accu[key] = value.kind_of?(Hash) ? dehash.call(value) : value + accu + end + end + end + + module FlatParamsEncoder + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def self.escape(s) + return s.to_s.gsub(ESCAPE_RE) { + '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def self.unescape(s) + CGI.unescape(s.to_s) + end + + def self.encode(params) + return nil if params == nil + + if !params.is_a?(Array) + if !params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = '' + params.each do |key, value| + encoded_key = escape(key) + value = value.to_s if value == true || value == false + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = escape(sub_value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = escape(value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + return buffer.chop + end + + def self.decode(query) + empty_accumulator = {} + return nil if query == nil + split_query = (query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + pair[0] = unescape(pair[0]) + pair[1] = true if pair[1].nil? + if pair[1].respond_to?(:to_str) + pair[1] = unescape(pair[1].to_str.gsub(/\+/, " ")) + end + if accu[pair[0]].kind_of?(Array) + accu[pair[0]] << pair[1] + elsif accu[pair[0]] + accu[pair[0]] = [accu[pair[0]], pair[1]] + else + accu[pair[0]] = pair[1] + end + accu + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/rack_builder.rb b/.gems/gems/faraday-0.9.0/lib/faraday/rack_builder.rb new file mode 100644 index 0000000..204ce41 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/rack_builder.rb @@ -0,0 +1,212 @@ +module Faraday + # A Builder that processes requests into responses by passing through an inner + # middleware stack (heavily inspired by Rack). + # + # Faraday::Connection.new(:url => 'http://sushi.com') do |builder| + # builder.request :url_encoded # Faraday::Request::UrlEncoded + # builder.adapter :net_http # Faraday::Adapter::NetHttp + # end + class RackBuilder + attr_accessor :handlers + + # Error raised when trying to modify the stack after calling `lock!` + class StackLocked < RuntimeError; end + + # borrowed from ActiveSupport::Dependencies::Reference & + # ActionDispatch::MiddlewareStack::Middleware + class Handler + @@constants_mutex = Mutex.new + @@constants = Hash.new { |h, k| + value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k) + @@constants_mutex.synchronize { h[k] = value } + } + + attr_reader :name + + def initialize(klass, *args, &block) + @name = klass.to_s + if klass.respond_to?(:name) + @@constants_mutex.synchronize { @@constants[@name] = klass } + end + @args, @block = args, block + end + + def klass() @@constants[@name] end + def inspect() @name end + + def ==(other) + if other.is_a? Handler + self.name == other.name + elsif other.respond_to? :name + klass == other + else + @name == other.to_s + end + end + + def build(app) + klass.new(app, *@args, &@block) + end + end + + def initialize(handlers = []) + @handlers = handlers + if block_given? + build(&Proc.new) + elsif @handlers.empty? + # default stack, if nothing else is configured + self.request :url_encoded + self.adapter Faraday.default_adapter + end + end + + def build(options = {}) + raise_if_locked + @handlers.clear unless options[:keep] + yield(self) if block_given? + end + + def [](idx) + @handlers[idx] + end + + # Locks the middleware stack to ensure no further modifications are possible. + def lock! + @handlers.freeze + end + + def locked? + @handlers.frozen? + end + + def use(klass, *args, &block) + if klass.is_a? Symbol + use_symbol(Faraday::Middleware, klass, *args, &block) + else + raise_if_locked + @handlers << self.class::Handler.new(klass, *args, &block) + end + end + + def request(key, *args, &block) + use_symbol(Faraday::Request, key, *args, &block) + end + + def response(key, *args, &block) + use_symbol(Faraday::Response, key, *args, &block) + end + + def adapter(key, *args, &block) + use_symbol(Faraday::Adapter, key, *args, &block) + end + + ## methods to push onto the various positions in the stack: + + def insert(index, *args, &block) + raise_if_locked + index = assert_index(index) + handler = self.class::Handler.new(*args, &block) + @handlers.insert(index, handler) + end + + alias_method :insert_before, :insert + + def insert_after(index, *args, &block) + index = assert_index(index) + insert(index + 1, *args, &block) + end + + def swap(index, *args, &block) + raise_if_locked + index = assert_index(index) + @handlers.delete_at(index) + insert(index, *args, &block) + end + + def delete(handler) + raise_if_locked + @handlers.delete(handler) + end + + # Processes a Request into a Response by passing it through this Builder's + # middleware stack. + # + # connection - Faraday::Connection + # request - Faraday::Request + # + # Returns a Faraday::Response. + def build_response(connection, request) + app.call(build_env(connection, request)) + end + + # The "rack app" wrapped in middleware. All requests are sent here. + # + # The builder is responsible for creating the app object. After this, + # the builder gets locked to ensure no further modifications are made + # to the middleware stack. + # + # Returns an object that responds to `call` and returns a Response. + def app + @app ||= begin + lock! + to_app(lambda { |env| + response = Response.new + response.finish(env) unless env.parallel? + env.response = response + }) + end + end + + def to_app(inner_app) + # last added handler is the deepest and thus closest to the inner app + @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) } + end + + def ==(other) + other.is_a?(self.class) && @handlers == other.handlers + end + + def dup + self.class.new(@handlers.dup) + end + + # ENV Keys + # :method - a symbolized request method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def build_env(connection, request) + Env.new(request.method, request.body, + connection.build_exclusive_url(request.path, request.params), + request.options, request.headers, connection.ssl, + connection.parallel_manager) + end + + private + + def raise_if_locked + raise StackLocked, "can't modify middleware stack after making a request" if locked? + end + + def use_symbol(mod, key, *args, &block) + use(mod.lookup_middleware(key), *args, &block) + end + + def assert_index(index) + idx = index.is_a?(Integer) ? index : @handlers.index(index) + raise "No such handler: #{index.inspect}" unless idx + idx + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request.rb new file mode 100644 index 0000000..481077f --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request.rb @@ -0,0 +1,92 @@ +module Faraday + # Used to setup urls, params, headers, and the request body in a sane manner. + # + # @connection.post do |req| + # req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1' + # req.headers['b'] = '2' # Header + # req.params['c'] = '3' # GET Param + # req['b'] = '2' # also Header + # req.body = 'abc' + # end + # + class Request < Struct.new(:method, :path, :params, :headers, :body, :options) + extend MiddlewareRegistry + + register_middleware File.expand_path('../request', __FILE__), + :url_encoded => [:UrlEncoded, 'url_encoded'], + :multipart => [:Multipart, 'multipart'], + :retry => [:Retry, 'retry'], + :authorization => [:Authorization, 'authorization'], + :basic_auth => [:BasicAuthentication, 'basic_authentication'], + :token_auth => [:TokenAuthentication, 'token_authentication'], + :instrumentation => [:Instrumentation, 'instrumentation'] + + def self.create(request_method) + new(request_method).tap do |request| + yield(request) if block_given? + end + end + + # Public: Replace params, preserving the existing hash type + def params=(hash) + if params + params.replace hash + else + super + end + end + + # Public: Replace request headers, preserving the existing hash type + def headers=(hash) + if headers + headers.replace hash + else + super + end + end + + def url(path, params = nil) + if path.respond_to? :query + if query = path.query + path = path.dup + path.query = nil + end + else + path, query = path.split('?', 2) + end + self.path = path + self.params.merge_query query, options.params_encoder + self.params.update(params) if params + end + + def [](key) + headers[key] + end + + def []=(key, value) + headers[key] = value + end + + # ENV Keys + # :method - a symbolized request method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def to_env(connection) + Env.new(method, body, connection.build_exclusive_url(path, params), + options, headers, connection.ssl, connection.parallel_manager) + end + end +end + diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/authorization.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/authorization.rb new file mode 100644 index 0000000..43b4528 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/authorization.rb @@ -0,0 +1,42 @@ +module Faraday + class Request::Authorization < Faraday::Middleware + KEY = "Authorization".freeze unless defined? KEY + + # Public + def self.header(type, token) + case token + when String, Symbol + "#{type} #{token}" + when Hash + build_hash(type.to_s, token) + else + raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}" + end + end + + # Internal + def self.build_hash(type, hash) + offset = KEY.size + type.size + 3 + comma = ",\n#{' ' * offset}" + values = [] + hash.each do |key, value| + values << "#{key}=#{value.to_s.inspect}" + end + "#{type} #{values * comma}" + end + + def initialize(app, type, token) + @header_value = self.class.header(type, token) + super(app) + end + + # Public + def call(env) + unless env.request_headers[KEY] + env.request_headers[KEY] = @header_value + end + @app.call(env) + end + end +end + diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/basic_authentication.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/basic_authentication.rb new file mode 100644 index 0000000..54c8dee --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/basic_authentication.rb @@ -0,0 +1,13 @@ +require 'base64' + +module Faraday + class Request::BasicAuthentication < Request.load_middleware(:authorization) + # Public + def self.header(login, pass) + value = Base64.encode64([login, pass].join(':')) + value.gsub!("\n", '') + super(:Basic, value) + end + end +end + diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/instrumentation.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/instrumentation.rb new file mode 100644 index 0000000..42af8bc --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/instrumentation.rb @@ -0,0 +1,36 @@ +module Faraday + class Request::Instrumentation < Faraday::Middleware + class Options < Faraday::Options.new(:name, :instrumenter) + def name + self[:name] ||= 'request.faraday' + end + + def instrumenter + self[:instrumenter] ||= ActiveSupport::Notifications + end + end + + # Public: Instruments requests using Active Support. + # + # Measures time spent only for synchronous requests. + # + # Examples + # + # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env| + # url = env[:url] + # http_method = env[:method].to_s.upcase + # duration = ends - starts + # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration] + # end + def initialize(app, options = nil) + super(app) + @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter) + end + + def call(env) + @instrumenter.instrument(@name, env) do + @app.call(env) + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/multipart.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/multipart.rb new file mode 100644 index 0000000..38b452a --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/multipart.rb @@ -0,0 +1,63 @@ +require File.expand_path("../url_encoded", __FILE__) + +module Faraday + class Request::Multipart < Request::UrlEncoded + self.mime_type = 'multipart/form-data'.freeze + DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY + + def call(env) + match_content_type(env) do |params| + env.request.boundary ||= DEFAULT_BOUNDARY + env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}" + env.body = create_multipart(env, params) + end + @app.call env + end + + def process_request?(env) + type = request_type(env) + env.body.respond_to?(:each_key) and !env.body.empty? and ( + (type.empty? and has_multipart?(env.body)) or + type == self.class.mime_type + ) + end + + def has_multipart?(obj) + # string is an enum in 1.8, returning list of itself + if obj.respond_to?(:each) && !obj.is_a?(String) + (obj.respond_to?(:values) ? obj.values : obj).each do |val| + return true if (val.respond_to?(:content_type) || has_multipart?(val)) + end + end + false + end + + def create_multipart(env, params) + boundary = env.request.boundary + parts = process_params(params) do |key, value| + Faraday::Parts::Part.new(boundary, key, value) + end + parts << Faraday::Parts::EpiloguePart.new(boundary) + + body = Faraday::CompositeReadIO.new(parts) + env.request_headers[Faraday::Env::ContentLength] = body.length.to_s + return body + end + + def process_params(params, prefix = nil, pieces = nil, &block) + params.inject(pieces || []) do |all, (key, value)| + key = "#{prefix}[#{key}]" if prefix + + case value + when Array + values = value.inject([]) { |a,v| a << [nil, v] } + process_params(values, key, all, &block) + when Hash + process_params(value, key, all, &block) + else + all << block.call(key, value) + end + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/retry.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/retry.rb new file mode 100644 index 0000000..0459b67 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/retry.rb @@ -0,0 +1,118 @@ +module Faraday + # Catches exceptions and retries each request a limited number of times. + # + # By default, it retries 2 times and handles only timeout exceptions. It can + # be configured with an arbitrary number of retries, a list of exceptions to + # handle, a retry interval, a percentage of randomness to add to the retry + # interval, and a backoff factor. + # + # Examples + # + # Faraday.new do |conn| + # conn.request :retry, max: 2, interval: 0.05, + # interval_randomness: 0.5, backoff_factor: 2 + # exceptions: [CustomException, 'Timeout::Error'] + # conn.adapter ... + # end + # + # This example will result in a first interval that is random between 0.05 and 0.075 and a second + # interval that is random between 0.1 and 0.15 + # + class Request::Retry < Faraday::Middleware + class Options < Faraday::Options.new(:max, :interval, :interval_randomness, :backoff_factor, :exceptions) + def self.from(value) + if Fixnum === value + new(value) + else + super(value) + end + end + + def max + (self[:max] ||= 2).to_i + end + + def interval + (self[:interval] ||= 0).to_f + end + + def interval_randomness + (self[:interval_randomness] ||= 0).to_i + end + + def backoff_factor + (self[:backoff_factor] ||= 1).to_f + end + + def exceptions + Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error', + Error::TimeoutError]) + end + + end + + # Public: Initialize middleware + # + # Options: + # max - Maximum number of retries (default: 2) + # interval - Pause in seconds between retries (default: 0) + # interval_randomness - The maximum random interval amount expressed + # as a float between 0 and 1 to use in addition to the + # interval. (default: 0) + # backoff_factor - The amount to multiple each successive retry's + # interval amount by in order to provide backoff + # (default: 1) + # exceptions - The list of exceptions to handle. Exceptions can be + # given as Class, Module, or String. (default: + # [Errno::ETIMEDOUT, Timeout::Error, + # Error::TimeoutError]) + def initialize(app, options = nil) + super(app) + @options = Options.from(options) + @errmatch = build_exception_matcher(@options.exceptions) + end + + def sleep_amount(retries) + retry_index = @options.max - retries + current_interval = @options.interval * (@options.backoff_factor ** retry_index) + random_interval = rand * @options.interval_randomness.to_f * @options.interval + current_interval + random_interval + end + + def call(env) + retries = @options.max + request_body = env[:body] + begin + env[:body] = request_body # after failure env[:body] is set to the response body + @app.call(env) + rescue @errmatch + if retries > 0 + retries -= 1 + sleep sleep_amount(retries + 1) + retry + end + raise + end + end + + # Private: construct an exception matcher object. + # + # An exception matcher for the rescue clause can usually be any object that + # responds to `===`, but for Ruby 1.8 it has to be a Class or Module. + def build_exception_matcher(exceptions) + matcher = Module.new + (class << matcher; self; end).class_eval do + define_method(:===) do |error| + exceptions.any? do |ex| + if ex.is_a? Module + error.is_a? ex + else + error.class.to_s == ex.to_s + end + end + end + end + matcher + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/token_authentication.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/token_authentication.rb new file mode 100644 index 0000000..2558608 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/token_authentication.rb @@ -0,0 +1,15 @@ +module Faraday + class Request::TokenAuthentication < Request.load_middleware(:authorization) + # Public + def self.header(token, options = nil) + options ||= {} + options[:token] = token + super(:Token, options) + end + + def initialize(app, token, options = nil) + super(app, token, options) + end + end +end + diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/request/url_encoded.rb b/.gems/gems/faraday-0.9.0/lib/faraday/request/url_encoded.rb new file mode 100644 index 0000000..b02a266 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/request/url_encoded.rb @@ -0,0 +1,36 @@ +module Faraday + class Request::UrlEncoded < Faraday::Middleware + CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE + + class << self + attr_accessor :mime_type + end + self.mime_type = 'application/x-www-form-urlencoded'.freeze + + def call(env) + match_content_type(env) do |data| + params = Faraday::Utils::ParamsHash[data] + env.body = params.to_query(env.params_encoder) + end + @app.call env + end + + def match_content_type(env) + if process_request?(env) + env.request_headers[CONTENT_TYPE] ||= self.class.mime_type + yield(env.body) unless env.body.respond_to?(:to_str) + end + end + + def process_request?(env) + type = request_type(env) + env.body and (type.empty? or type == self.class.mime_type) + end + + def request_type(env) + type = env.request_headers[CONTENT_TYPE].to_s + type = type.split(';', 2).first if type.index(';') + type + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/response.rb b/.gems/gems/faraday-0.9.0/lib/faraday/response.rb new file mode 100644 index 0000000..fa55958 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/response.rb @@ -0,0 +1,93 @@ +require 'forwardable' + +module Faraday + class Response + # Used for simple response middleware. + class Middleware < Faraday::Middleware + def call(env) + @app.call(env).on_complete do |environment| + on_complete(environment) + end + end + + # Override this to modify the environment after the response has finished. + # Calls the `parse` method if defined + def on_complete(env) + env.body = parse(env.body) if respond_to?(:parse) && env.parse_body? + end + end + + extend Forwardable + extend MiddlewareRegistry + + register_middleware File.expand_path('../response', __FILE__), + :raise_error => [:RaiseError, 'raise_error'], + :logger => [:Logger, 'logger'] + + def initialize(env = nil) + @env = Env.from(env) if env + @on_complete_callbacks = [] + end + + attr_reader :env + + def_delegators :env, :to_hash + + def status + finished? ? env.status : nil + end + + def headers + finished? ? env.response_headers : {} + end + def_delegator :headers, :[] + + def body + finished? ? env.body : nil + end + + def finished? + !!env + end + + def on_complete + if not finished? + @on_complete_callbacks << Proc.new + else + yield(env) + end + return self + end + + def finish(env) + raise "response already finished" if finished? + @env = Env.from(env) + @on_complete_callbacks.each { |callback| callback.call(env) } + return self + end + + def success? + finished? && env.success? + end + + # because @on_complete_callbacks cannot be marshalled + def marshal_dump + !finished? ? nil : { + :status => @env.status, :body => @env.body, + :response_headers => @env.response_headers + } + end + + def marshal_load(env) + @env = Env.from(env) + end + + # Expand the env with more properties, without overriding existing ones. + # Useful for applying request params after restoring a marshalled Response. + def apply_request(request_env) + raise "response didn't finish yet" unless finished? + @env = Env.from(request_env).update(@env) + return self + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/response/logger.rb b/.gems/gems/faraday-0.9.0/lib/faraday/response/logger.rb new file mode 100644 index 0000000..cab7f1b --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/response/logger.rb @@ -0,0 +1,34 @@ +require 'forwardable' + +module Faraday + class Response::Logger < Response::Middleware + extend Forwardable + + def initialize(app, logger = nil) + super(app) + @logger = logger || begin + require 'logger' + ::Logger.new(STDOUT) + end + end + + def_delegators :@logger, :debug, :info, :warn, :error, :fatal + + def call(env) + info "#{env.method} #{env.url.to_s}" + debug('request') { dump_headers env.request_headers } + super + end + + def on_complete(env) + info('Status') { env.status.to_s } + debug('response') { dump_headers env.response_headers } + end + + private + + def dump_headers(headers) + headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n") + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/response/raise_error.rb b/.gems/gems/faraday-0.9.0/lib/faraday/response/raise_error.rb new file mode 100644 index 0000000..437762b --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/response/raise_error.rb @@ -0,0 +1,21 @@ +module Faraday + class Response::RaiseError < Response::Middleware + ClientErrorStatuses = 400...600 + + def on_complete(env) + case env[:status] + when 404 + raise Faraday::Error::ResourceNotFound, response_values(env) + when 407 + # mimic the behavior that we get with proxy requests with HTTPS + raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + when ClientErrorStatuses + raise Faraday::Error::ClientError, response_values(env) + end + end + + def response_values(env) + {:status => env.status, :headers => env.response_headers, :body => env.body} + end + end +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/upload_io.rb b/.gems/gems/faraday-0.9.0/lib/faraday/upload_io.rb new file mode 100644 index 0000000..9130d15 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/upload_io.rb @@ -0,0 +1,67 @@ +begin + require 'composite_io' + require 'parts' + require 'stringio' +rescue LoadError + $stderr.puts "Install the multipart-post gem." + raise +end + +module Faraday + # Similar but not compatible with ::CompositeReadIO provided by multipart-post. + class CompositeReadIO + def initialize(*parts) + @parts = parts.flatten + @ios = @parts.map { |part| part.to_io } + @index = 0 + end + + def length + @parts.inject(0) { |sum, part| sum + part.length } + end + + def rewind + @ios.each { |io| io.rewind } + @index = 0 + end + + # Read from IOs in order until `length` bytes have been received. + def read(length = nil, outbuf = nil) + got_result = false + outbuf = outbuf ? outbuf.replace("") : "" + + while io = current_io + if result = io.read(length) + got_result ||= !result.nil? + result.force_encoding("BINARY") if result.respond_to?(:force_encoding) + outbuf << result + length -= result.length if length + break if length == 0 + end + advance_io + end + (!got_result && length) ? nil : outbuf + end + + def close + @ios.each { |io| io.close } + end + + def ensure_open_and_readable + # Rubinius compatibility + end + + private + + def current_io + @ios[@index] + end + + def advance_io + @index += 1 + end + end + + UploadIO = ::UploadIO + Parts = ::Parts +end diff --git a/.gems/gems/faraday-0.9.0/lib/faraday/utils.rb b/.gems/gems/faraday-0.9.0/lib/faraday/utils.rb new file mode 100644 index 0000000..1cd6526 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/lib/faraday/utils.rb @@ -0,0 +1,297 @@ +require 'thread' +Faraday.require_libs 'parameters' + +module Faraday + module Utils + extend self + + # Adapted from Rack::Utils::HeaderHash + class Headers < ::Hash + def self.from(value) + new(value) + end + + def initialize(hash = nil) + super() + @names = {} + self.update(hash || {}) + end + + # need to synchronize concurrent writes to the shared KeyMap + keymap_mutex = Mutex.new + + # symbol -> string mapper + cache + KeyMap = Hash.new do |map, key| + value = if key.respond_to?(:to_str) + key + else + key.to_s.split('_'). # :user_agent => %w(user agent) + each { |w| w.capitalize! }. # => %w(User Agent) + join('-') # => "User-Agent" + end + keymap_mutex.synchronize { map[key] = value } + end + KeyMap[:etag] = "ETag" + + def [](k) + k = KeyMap[k] + super(k) || super(@names[k.downcase]) + end + + def []=(k, v) + k = KeyMap[k] + k = (@names[k.downcase] ||= k) + # join multiple values with a comma + v = v.to_ary.join(', ') if v.respond_to? :to_ary + super(k, v) + end + + def fetch(k, *args, &block) + k = KeyMap[k] + key = @names.fetch(k.downcase, k) + super(key, *args, &block) + end + + def delete(k) + k = KeyMap[k] + if k = @names[k.downcase] + @names.delete k.downcase + super(k) + end + end + + def include?(k) + @names.include? k.downcase + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + alias_method :update, :merge! + + def merge(other) + hash = dup + hash.merge! other + end + + def replace(other) + clear + self.update other + self + end + + def to_hash() ::Hash.new.update(self) end + + def parse(header_string) + return unless header_string && !header_string.empty? + header_string.split(/\r\n/). + tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line + map { |h| h.split(/:\s+/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines + each { |key, value| + # join multiple values with a comma + if self[key] + self[key] << ', ' << value + else + self[key] = value + end + } + end + end + + # hash with stringified keys + class ParamsHash < Hash + def [](key) + super(convert_key(key)) + end + + def []=(key, value) + super(convert_key(key), value) + end + + def delete(key) + super(convert_key(key)) + end + + def include?(key) + super(convert_key(key)) + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def update(params) + params.each do |key, value| + self[key] = value + end + self + end + alias_method :merge!, :update + + def merge(params) + dup.update(params) + end + + def replace(other) + clear + update(other) + end + + def merge_query(query, encoder = nil) + if query && !query.empty? + update((encoder || Utils.default_params_encoder).decode(query)) + end + self + end + + def to_query(encoder = nil) + (encoder || Utils.default_params_encoder).encode(self) + end + + private + + def convert_key(key) + key.to_s + end + end + + def build_query(params) + FlatParamsEncoder.encode(params) + end + + def build_nested_query(params) + NestedParamsEncoder.encode(params) + end + + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def escape(s) + s.to_s.gsub(ESCAPE_RE) {|match| + '%' + match.unpack('H2' * match.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def unescape(s) CGI.unescape s.to_s end + + DEFAULT_SEP = /[&;] */n + + # Adapted from Rack + def parse_query(query) + FlatParamsEncoder.decode(query) + end + + def parse_nested_query(query) + NestedParamsEncoder.decode(query) + end + + def default_params_encoder + @default_params_encoder ||= NestedParamsEncoder + end + + class << self + attr_writer :default_params_encoder + end + + # Stolen from Rack + def normalize_params(params, name, v = nil) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + return if k.empty? + + if after == "" + if params[k] + params[k] = Array[params[k]] unless params[k].kind_of?(Array) + params[k] << v + else + params[k] = v + end + elsif after == "[]" + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) + normalize_params(params[k].last, child_key, v) + else + params[k] << normalize_params({}, child_key, v) + end + else + params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) + params[k] = normalize_params(params[k], after, v) + end + + return params + end + + # Normalize URI() behavior across Ruby versions + # + # url - A String or URI. + # + # Returns a parsed URI. + def URI(url) + if url.respond_to?(:host) + url + elsif url.respond_to?(:to_str) + default_uri_parser.call(url) + else + raise ArgumentError, "bad argument (expected URI object or URI string)" + end + end + + def default_uri_parser + @default_uri_parser ||= begin + require 'uri' + Kernel.method(:URI) + end + end + + def default_uri_parser=(parser) + @default_uri_parser = if parser.respond_to?(:call) || parser.nil? + parser + else + parser.method(:parse) + end + end + + # Receives a String or URI and returns just the path with the query string sorted. + def normalize_path(url) + url = URI(url) + (url.path.start_with?('/') ? url.path : '/' + url.path) + + (url.query ? "?#{sort_query_params(url.query)}" : "") + end + + # Recursive hash update + def deep_merge!(target, hash) + hash.each do |key, value| + if Hash === value and Hash === target[key] + target[key] = deep_merge(target[key], value) + else + target[key] = value + end + end + target + end + + # Recursive hash merge + def deep_merge(source, hash) + deep_merge!(source.dup, hash) + end + + protected + + def sort_query_params(query) + query.split('&').sort.join('&') + end + end +end diff --git a/.gems/gems/faraday-0.9.0/script/console b/.gems/gems/faraday-0.9.0/script/console new file mode 100755 index 0000000..5d18d7a --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/console @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Usage: script/console +# Starts an IRB console with this library loaded. + +gemspec="$(ls *.gemspec | head -1)" + +exec bundle exec irb -r "${gemspec%.*}" diff --git a/.gems/gems/faraday-0.9.0/script/generate_certs b/.gems/gems/faraday-0.9.0/script/generate_certs new file mode 100755 index 0000000..30063f7 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/generate_certs @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby +# Usage: generate_certs +# Generate test certs for testing Faraday with SSL + +require 'openssl' +require 'fileutils' + +$shell = ARGV.include? '-s' + +# Adapted from WEBrick::Utils. Skips cert extensions so it +# can be used as a CA bundle +def create_self_signed_cert(bits, cn, comment) + rsa = OpenSSL::PKey::RSA.new(bits) + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 1 + name = OpenSSL::X509::Name.new(cn) + cert.subject = name + cert.issuer = name + cert.not_before = Time.now + cert.not_after = Time.now + (365*24*60*60) + cert.public_key = rsa.public_key + cert.sign(rsa, OpenSSL::Digest::SHA1.new) + return [cert, rsa] +end + +def write(file, contents, env_var) + FileUtils.mkdir_p(File.dirname(file)) + File.open(file, 'w') {|f| f.puts(contents) } + puts %(export #{env_var}="#{file}") if $shell +end + + +# One cert / CA for ease of testing when ignoring verification +cert, key = create_self_signed_cert(1024, [['CN', 'localhost']], 'Faraday Test CA') +write 'tmp/faraday-cert.key', key, 'SSL_KEY' +write 'tmp/faraday-cert.crt', cert, 'SSL_FILE' + +# And a second CA to prove that verification can fail +cert, key = create_self_signed_cert(1024, [['CN', 'real-ca.com']], 'A different CA') +write 'tmp/faraday-different-ca-cert.key', key, 'SSL_KEY_ALT' +write 'tmp/faraday-different-ca-cert.crt', cert, 'SSL_FILE_ALT' diff --git a/.gems/gems/faraday-0.9.0/script/package b/.gems/gems/faraday-0.9.0/script/package new file mode 100755 index 0000000..926f489 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/package @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Usage: script/gem +# Updates the gemspec and builds a new gem in the pkg directory. + +mkdir -p pkg +gem build *.gemspec +mv *.gem pkg diff --git a/.gems/gems/faraday-0.9.0/script/proxy-server b/.gems/gems/faraday-0.9.0/script/proxy-server new file mode 100755 index 0000000..e5ba4bc --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/proxy-server @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby +# Usage: script/proxy-server [-p PORT] [-u USER:PASSWORD] +require 'webrick' +require 'webrick/httpproxy' + +port = 4001 + +if found = ARGV.index('-p') + port = ARGV[found + 1].to_i +end +if found = ARGV.index('-u') + username, password = ARGV[found + 1].split(':', 2) +end + +match_credentials = lambda { |credentials| + got_username, got_password = credentials.to_s.unpack("m*")[0].split(":", 2) + got_username == username && got_password == password +} + +log_io = $stdout +log_io.sync = true + +webrick_opts = { + :Port => port, :Logger => WEBrick::Log::new(log_io), + :AccessLog => [[log_io, "[%{X-Faraday-Adapter}i] %m %U -> %s %b"]], + :ProxyAuthProc => lambda { |req, res| + if username + type, credentials = req.header['proxy-authorization'].first.to_s.split(/\s+/, 2) + unless "Basic" == type && match_credentials.call(credentials) + res['proxy-authenticate'] = %{Basic realm="testing"} + raise WEBrick::HTTPStatus::ProxyAuthenticationRequired + end + end + } +} + +proxy = WEBrick::HTTPProxyServer.new(webrick_opts) + +trap(:TERM) { proxy.shutdown } +trap(:INT) { proxy.shutdown } + +proxy.start diff --git a/.gems/gems/faraday-0.9.0/script/release b/.gems/gems/faraday-0.9.0/script/release new file mode 100755 index 0000000..ed73118 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/release @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Usage: script/release +# Build the package, tag a commit, push it to origin, and then release the +# package publicly. + +set -e + +version="$(script/package | grep Version: | awk '{print $2}')" +[ -n "$version" ] || exit 1 + +git commit --allow-empty -a -m "Release $version" +git tag "v$version" +git push origin +git push origin "v$version" +git push legacy +git push legacy "v$version" +gem push pkg/*-${version}.gem diff --git a/.gems/gems/faraday-0.9.0/script/server b/.gems/gems/faraday-0.9.0/script/server new file mode 100755 index 0000000..f497d35 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/server @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +old_verbose, $VERBOSE = $VERBOSE, nil +begin + require File.expand_path('../../test/live_server', __FILE__) +ensure + $VERBOSE = old_verbose +end +require 'webrick' + +port = 4000 +if found = ARGV.index('-p') + port = ARGV[found + 1].to_i +end + +log_io = $stdout +log_io.sync = true + +webrick_opts = { + :Port => port, :Logger => WEBrick::Log::new(log_io), + :AccessLog => [[log_io, "[%{X-Faraday-Adapter}i] %m %U -> %s %b"]] +} + +if ENV['SSL_KEY'] + require 'openssl' + require 'webrick/https' + webrick_opts.update \ + :SSLEnable => true, + :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read(ENV['SSL_KEY'])), + :SSLCertificate => OpenSSL::X509::Certificate.new(File.read(ENV['SSL_FILE'])), + :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE +end + +Rack::Handler::WEBrick.run(Faraday::LiveServer, webrick_opts) do |server| + trap(:INT) { server.stop } + trap(:TERM) { server.stop } +end diff --git a/.gems/gems/faraday-0.9.0/script/test b/.gems/gems/faraday-0.9.0/script/test new file mode 100755 index 0000000..beb9af2 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/script/test @@ -0,0 +1,172 @@ +#!/usr/bin/env bash +# Usage: script/test [file] [adapter]... -- [test/unit options] +# Runs the test suite against a local server spawned automatically in a +# thread. After tests are done, the server is shut down. +# +# If filename arguments are given, only those files are run. If arguments given +# are not filenames, they are taken as words that filter the list of files to run. +# +# Examples: +# +# $ script/test +# $ script/test test/env_test.rb +# $ script/test excon typhoeus +# +# # Run only tests matching /ssl/ for the net_http adapter, with SSL enabled. +# $ SSL=yes script/test net_http -- -n /ssl/ +# +# # Run against multiple rbenv versions +# $ RBENV_VERSIONS="1.9.3-p194 ree-1.8.7-2012.02" script/test +set -e + +if [[ "$RUBYOPT" != *"bundler/setup"* ]]; then + export RUBYOPT="-rbundler/setup $RUBYOPT" +fi + +port=3999 +proxy_port=3998 +scheme=http + +if [ "$SSL" = "yes" ]; then + scheme=https + if [ -z "$SSL_KEY" ] || [ -z "$SSL_FILE" ]; then + eval "$(script/generate_certs -s)" + fi +fi + +find_test_files() { + find "$1" -name '*_test.rb' +} + +filter_matching() { + pattern="$1" + shift + for line in "$@"; do + [[ $line == *"$pattern"* ]] && echo "$line" + done +} + +start_server() { + mkdir -p log + script/server -p $port >log/test.log 2>&1 & + echo $! +} + +start_proxy() { + mkdir -p log + script/proxy-server -p $proxy_port -u "faraday@test.local:there is cake" >log/proxy.log 2>&1 & + echo $! +} + +server_started() { + lsof -i :${1?} >/dev/null +} + +timestamp() { + date +%s +} + +wait_for_server() { + timeout=$(( `timestamp` + $1 )) + while true; do + if server_started "$2"; then + break + elif [ `timestamp` -gt "$timeout" ]; then + echo "timed out after $1 seconds" >&2 + return 1 + fi + done +} + +filtered= +IFS=$'\n' test_files=($(find_test_files "test")) +declare -a explicit_files + +# Process filter arguments: +# - test filenames as taken as-is +# - other words are taken as pattern to match the list of known files against +# - arguments after "--" are forwarded to the ruby process +while [ $# -gt 0 ]; do + arg="$1" + shift + if [ "$arg" = "--" ]; then + break + elif [ -f "$arg" ]; then + filtered=true + explicit_files[${#explicit_files[@]}+1]="$arg" + else + filtered=true + IFS=$'\n' explicit_files=( + ${explicit_files[@]} + $(filter_matching "$arg" "${test_files[@]}" || true) + ) + fi +done + +# If there were filter args, replace test files list with the results +if [ -n "$filtered" ]; then + if [ ${#explicit_files[@]} -eq 0 ]; then + echo "Error: no test files match" >&2 + exit 1 + else + test_files=(${explicit_files[@]}) + echo running "${test_files[@]}" + fi +fi + +# If there are any adapter tests, spin up the HTTP server +if [ -n "$(filter_matching "adapters" "${test_files[@]}")" ]; then + if server_started $port; then + echo "aborted: another instance of server running on $port" >&2 + exit 1 + fi + server_pid=$(start_server) + proxy_pid=$(start_proxy) + wait_for_server 30 $port || { + cat log/test.log + kill "$server_pid" + kill "$proxy_pid" + exit 1 + } + wait_for_server 5 $proxy_port + cleanup() { + if [ $? -ne 0 ] && [ -n "$TRAVIS" ]; then + cat log/test.log + fi + kill "$server_pid" + kill "$proxy_pid" + } + trap cleanup INT EXIT + export LIVE="${scheme}://localhost:${port}" + export LIVE_PROXY="http://faraday%40test.local:there%20is%20cake@localhost:${proxy_port}" +fi + +warnings="${TMPDIR:-/tmp}/faraday-warnings.$$" + +run_test_files() { + # Save warnings on stderr to a separate file + RUBYOPT="$RUBYOPT -w" ruby -e 'while f=ARGV.shift and f!="--"; load f; end' "${test_files[@]}" -- "$@" \ + 2> >(tee >(grep 'warning:' >"$warnings") | grep -v 'warning:') +} + +check_warnings() { + # Display Ruby warnings from this project's source files. Abort if any were found. + num="$(grep -F "$PWD" "$warnings" | grep -v "${PWD}/bundle" | sort | uniq -c | sort -rn | tee /dev/stderr | wc -l)" + rm -f "$warnings" + if [ "$num" -gt 0 ]; then + echo "FAILED: this test suite doesn't tolerate Ruby syntax warnings!" >&2 + exit 1 + fi +} + +if [ -n "$RBENV_VERSIONS" ]; then + IFS=' ' versions=($RBENV_VERSIONS) + for version in "${versions[@]}"; do + echo "[${version}]" + RBENV_VERSION="$version" run_test_files "$@" + done +else + run_test_files "$@" +fi + +check_warnings diff --git a/.gems/gems/faraday-0.9.0/test/adapters/default_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/default_test.rb new file mode 100644 index 0000000..400baab --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/default_test.rb @@ -0,0 +1,14 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class DefaultTest < Faraday::TestCase + + def adapter() :default end + + Integration.apply(self, :NonParallel) do + # default stack is not configured with Multipart + undef :test_POST_sends_files + end + + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/em_http_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/em_http_test.rb new file mode 100644 index 0000000..f122090 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/em_http_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class EMHttpTest < Faraday::TestCase + + def adapter() :em_http end + + Integration.apply(self, :Parallel) do + # https://github.com/eventmachine/eventmachine/pull/289 + undef :test_timeout + + def test_binds_local_socket + host = '1.2.3.4' + conn = create_connection :request => { :bind => { :host => host } } + assert_equal host, conn.options[:bind][:host] + end + end unless jruby? and ssl_mode? + # https://github.com/eventmachine/eventmachine/issues/180 + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/em_synchrony_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/em_synchrony_test.rb new file mode 100644 index 0000000..59cdef7 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/em_synchrony_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class EMSynchronyTest < Faraday::TestCase + + def adapter() :em_synchrony end + + Integration.apply(self, :Parallel) do + # https://github.com/eventmachine/eventmachine/pull/289 + undef :test_timeout + + def test_binds_local_socket + host = '1.2.3.4' + conn = create_connection :request => { :bind => { :host => host } } + #put conn.get('/who-am-i').body + assert_equal host, conn.options[:bind][:host] + end + end unless RUBY_VERSION < '1.9' or jruby? + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/excon_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/excon_test.rb new file mode 100644 index 0000000..f7b9967 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/excon_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class ExconTest < Faraday::TestCase + + def adapter() :excon end + + Integration.apply(self, :NonParallel) do + # https://github.com/geemus/excon/issues/126 ? + undef :test_timeout if ssl_mode? + + # Excon lets OpenSSL::SSL::SSLError be raised without any way to + # distinguish whether it happened because of a 407 proxy response + undef :test_proxy_auth_fail if ssl_mode? + + # https://github.com/geemus/excon/issues/358 + undef :test_connection_error if RUBY_VERSION >= '2.1.0' + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/httpclient_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/httpclient_test.rb new file mode 100644 index 0000000..ba93ccc --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/httpclient_test.rb @@ -0,0 +1,21 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class HttpclientTest < Faraday::TestCase + + def adapter() :httpclient end + + Integration.apply(self, :NonParallel) do + def setup + require 'httpclient' unless defined?(HTTPClient) + HTTPClient::NO_PROXY_HOSTS.delete('localhost') + end + + def test_binds_local_socket + host = '1.2.3.4' + conn = create_connection :request => { :bind => { :host => host } } + assert_equal host, conn.options[:bind][:host] + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/integration.rb b/.gems/gems/faraday-0.9.0/test/adapters/integration.rb new file mode 100644 index 0000000..45445fe --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/integration.rb @@ -0,0 +1,254 @@ +require 'forwardable' +require File.expand_path("../../helper", __FILE__) +Faraday.require_lib 'autoload' + +module Adapters + # Adapter integration tests. To use, implement two methods: + # + # `#adapter` required. returns a symbol for the adapter middleware name + # `#adapter_options` optional. extra arguments for building an adapter + module Integration + def self.apply(base, *extra_features) + if base.live_server? + features = [:Common] + features.concat extra_features + features << :SSL if base.ssl_mode? + features.each {|name| base.send(:include, self.const_get(name)) } + yield if block_given? + elsif !defined? @warned + warn "Warning: Not running integration tests against a live server." + warn "Start the server `ruby test/live_server.rb` and set the LIVE=1 env variable." + @warned = true + end + end + + module Parallel + def test_in_parallel + resp1, resp2 = nil, nil + + connection = create_connection + connection.in_parallel do + resp1 = connection.get('echo?a=1') + resp2 = connection.get('echo?b=2') + assert connection.in_parallel? + assert_nil resp1.body + assert_nil resp2.body + end + assert !connection.in_parallel? + assert_equal 'get ?{"a"=>"1"}', resp1.body + assert_equal 'get ?{"b"=>"2"}', resp2.body + end + end + + module NonParallel + def test_no_parallel_support + connection = create_connection + response = nil + + err = capture_warnings do + connection.in_parallel do + response = connection.get('echo').body + end + end + assert response + assert_match "no parallel-capable adapter on Faraday stack", err + assert_match __FILE__, err + end + end + + module Compression + def test_GET_handles_compression + res = get('echo_header', :name => 'accept-encoding') + assert_match(/gzip;.+\bdeflate\b/, res.body) + end + end + + module SSL + def test_GET_ssl_fails_with_bad_cert + ca_file = 'tmp/faraday-different-ca-cert.crt' + conn = create_connection(:ssl => {:ca_file => ca_file}) + err = assert_raises Faraday::SSLError do + conn.get('/ssl') + end + assert_includes err.message, "certificate" + end + end + + module Common + extend Forwardable + def_delegators :create_connection, :get, :head, :put, :post, :patch, :delete, :run_request + + def test_GET_retrieves_the_response_body + assert_equal 'get', get('echo').body + end + + def test_GET_send_url_encoded_params + assert_equal %(get ?{"name"=>"zack"}), get('echo', :name => 'zack').body + end + + def test_GET_retrieves_the_response_headers + response = get('echo') + assert_match(/text\/plain/, response.headers['Content-Type'], 'original case fail') + assert_match(/text\/plain/, response.headers['content-type'], 'lowercase fail') + end + + def test_GET_handles_headers_with_multiple_values + assert_equal 'one, two', get('multi').headers['set-cookie'] + end + + def test_GET_with_body + response = get('echo') do |req| + req.body = {'bodyrock' => true} + end + assert_equal %(get {"bodyrock"=>"true"}), response.body + end + + def test_GET_sends_user_agent + response = get('echo_header', {:name => 'user-agent'}, :user_agent => 'Agent Faraday') + assert_equal 'Agent Faraday', response.body + end + + def test_GET_ssl + expected = self.class.ssl_mode?.to_s + assert_equal expected, get('ssl').body + end + + def test_POST_send_url_encoded_params + assert_equal %(post {"name"=>"zack"}), post('echo', :name => 'zack').body + end + + def test_POST_send_url_encoded_nested_params + resp = post('echo', 'name' => {'first' => 'zack'}) + assert_equal %(post {"name"=>{"first"=>"zack"}}), resp.body + end + + def test_POST_retrieves_the_response_headers + assert_match(/text\/plain/, post('echo').headers['content-type']) + end + + def test_POST_sends_files + resp = post('file') do |req| + req.body = {'uploaded_file' => Faraday::UploadIO.new(__FILE__, 'text/x-ruby')} + end + assert_equal "file integration.rb text/x-ruby #{File.size(__FILE__)}", resp.body + end + + def test_PUT_send_url_encoded_params + assert_equal %(put {"name"=>"zack"}), put('echo', :name => 'zack').body + end + + def test_PUT_send_url_encoded_nested_params + resp = put('echo', 'name' => {'first' => 'zack'}) + assert_equal %(put {"name"=>{"first"=>"zack"}}), resp.body + end + + def test_PUT_retrieves_the_response_headers + assert_match(/text\/plain/, put('echo').headers['content-type']) + end + + def test_PATCH_send_url_encoded_params + assert_equal %(patch {"name"=>"zack"}), patch('echo', :name => 'zack').body + end + + def test_OPTIONS + resp = run_request(:options, 'echo', nil, {}) + assert_equal 'options', resp.body + end + + def test_HEAD_retrieves_no_response_body + assert_equal '', head('echo').body + end + + def test_HEAD_retrieves_the_response_headers + assert_match(/text\/plain/, head('echo').headers['content-type']) + end + + def test_DELETE_retrieves_the_response_headers + assert_match(/text\/plain/, delete('echo').headers['content-type']) + end + + def test_DELETE_retrieves_the_body + assert_equal %(delete), delete('echo').body + end + + def test_timeout + conn = create_connection(:request => {:timeout => 1, :open_timeout => 1}) + assert_raises Faraday::Error::TimeoutError do + conn.get '/slow' + end + end + + def test_connection_error + assert_raises Faraday::Error::ConnectionFailed do + get 'http://localhost:4' + end + end + + def test_proxy + proxy_uri = URI(ENV['LIVE_PROXY']) + conn = create_connection(:proxy => proxy_uri) + + res = conn.get '/echo' + assert_equal 'get', res.body + + unless self.class.ssl_mode? + # proxy can't append "Via" header for HTTPS responses + assert_match(/:#{proxy_uri.port}$/, res['via']) + end + end + + def test_proxy_auth_fail + proxy_uri = URI(ENV['LIVE_PROXY']) + proxy_uri.password = 'WRONG' + conn = create_connection(:proxy => proxy_uri) + + err = assert_raises Faraday::Error::ConnectionFailed do + conn.get '/echo' + end + + unless self.class.ssl_mode? && self.class.jruby? + # JRuby raises "End of file reached" which cannot be distinguished from a 407 + assert_equal %{407 "Proxy Authentication Required "}, err.message + end + end + + def test_empty_body_response_represented_as_blank_string + response = get('204') + assert_equal '', response.body + end + + def adapter + raise NotImplementedError.new("Need to override #adapter") + end + + # extra options to pass when building the adapter + def adapter_options + [] + end + + def create_connection(options = {}) + if adapter == :default + builder_block = nil + else + builder_block = Proc.new do |b| + b.request :multipart + b.request :url_encoded + b.adapter adapter, *adapter_options + end + end + + server = self.class.live_server + url = '%s://%s:%d' % [server.scheme, server.host, server.port] + + options[:ssl] ||= {} + options[:ssl][:ca_file] ||= ENV['SSL_FILE'] + + Faraday::Connection.new(url, options, &builder_block).tap do |conn| + conn.headers['X-Faraday-Adapter'] = adapter.to_s + adapter_handler = conn.builder.handlers.last + conn.builder.insert_before adapter_handler, Faraday::Response::RaiseError + end + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/logger_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/logger_test.rb new file mode 100644 index 0000000..7a71ca6 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/logger_test.rb @@ -0,0 +1,37 @@ +require File.expand_path('../../helper', __FILE__) +require 'stringio' +require 'logger' + +module Adapters + class LoggerTest < Faraday::TestCase + def setup + @io = StringIO.new + @logger = Logger.new(@io) + @logger.level = Logger::DEBUG + + @conn = Faraday.new do |b| + b.response :logger, @logger + b.adapter :test do |stubs| + stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] } + end + end + @resp = @conn.get '/hello', nil, :accept => 'text/html' + end + + def test_still_returns_output + assert_equal 'hello', @resp.body + end + + def test_logs_method_and_url + assert_match "get http:/hello", @io.string + end + + def test_logs_request_headers + assert_match %(Accept: "text/html), @io.string + end + + def test_logs_response_headers + assert_match %(Content-Type: "text/html), @io.string + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/net_http_persistent_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/net_http_persistent_test.rb new file mode 100644 index 0000000..edd986a --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/net_http_persistent_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class NetHttpPersistentTest < Faraday::TestCase + + def adapter() :net_http_persistent end + + Integration.apply(self, :NonParallel) do + def setup + if defined?(Net::HTTP::Persistent) + # work around problems with mixed SSL certificates + # https://github.com/drbrain/net-http-persistent/issues/45 + http = Net::HTTP::Persistent.new('Faraday') + http.ssl_cleanup(4) + end + end if ssl_mode? + end + + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/net_http_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/net_http_test.rb new file mode 100644 index 0000000..810fad4 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/net_http_test.rb @@ -0,0 +1,14 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class NetHttpTest < Faraday::TestCase + + def adapter() :net_http end + + behaviors = [:NonParallel] + behaviors << :Compression if RUBY_VERSION >= '1.9' + + Integration.apply(self, *behaviors) + + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/patron_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/patron_test.rb new file mode 100644 index 0000000..828d7fb --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/patron_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class Patron < Faraday::TestCase + + def adapter() :patron end + + Integration.apply(self, :NonParallel) do + # https://github.com/toland/patron/issues/34 + undef :test_PATCH_send_url_encoded_params + + # https://github.com/toland/patron/issues/52 + undef :test_GET_with_body + + # no support for SSL peer verification + undef :test_GET_ssl_fails_with_bad_cert if ssl_mode? + end unless jruby? + + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/rack_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/rack_test.rb new file mode 100644 index 0000000..545099c --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/rack_test.rb @@ -0,0 +1,31 @@ +require File.expand_path("../integration", __FILE__) +require File.expand_path('../../live_server', __FILE__) + +module Adapters + class RackTest < Faraday::TestCase + + def adapter() :rack end + + def adapter_options + [Faraday::LiveServer] + end + + # no Integration.apply because this doesn't require a server as a separate process + include Integration::Common + include Integration::NonParallel + + # not using shared test because error is swallowed by Sinatra + def test_timeout + conn = create_connection(:request => {:timeout => 1, :open_timeout => 1}) + begin + conn.get '/slow' + rescue Faraday::Error::ClientError + end + end + + # test not applicable + undef test_connection_error + undef test_proxy + undef test_proxy_auth_fail + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/test_middleware_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/test_middleware_test.rb new file mode 100644 index 0000000..2acd4a4 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/test_middleware_test.rb @@ -0,0 +1,114 @@ +require File.expand_path('../../helper', __FILE__) + +module Adapters + class TestMiddleware < Faraday::TestCase + Stubs = Faraday::Adapter.lookup_middleware(:test)::Stubs + def setup + @stubs = Stubs.new + @conn = Faraday.new do |builder| + builder.adapter :test, @stubs + end + @stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] } + @resp = @conn.get('/hello') + end + + def test_middleware_with_simple_path_sets_status + assert_equal 200, @resp.status + end + + def test_middleware_with_simple_path_sets_headers + assert_equal 'text/html', @resp.headers['Content-Type'] + end + + def test_middleware_with_simple_path_sets_body + assert_equal 'hello', @resp.body + end + + def test_middleware_can_be_called_several_times + assert_equal 'hello', @conn.get("/hello").body + end + + def test_middleware_with_get_params + @stubs.get('/param?a=1') { [200, {}, 'a'] } + assert_equal 'a', @conn.get('/param?a=1').body + end + + def test_middleware_ignores_unspecified_get_params + @stubs.get('/optional?a=1') { [200, {}, 'a'] } + assert_equal 'a', @conn.get('/optional?a=1&b=1').body + assert_equal 'a', @conn.get('/optional?a=1').body + assert_raises Faraday::Adapter::Test::Stubs::NotFound do + @conn.get('/optional') + end + end + + def test_middleware_with_http_headers + @stubs.get('/yo', { 'X-HELLO' => 'hello' }) { [200, {}, 'a'] } + @stubs.get('/yo') { [200, {}, 'b'] } + assert_equal 'a', @conn.get('/yo') { |env| env.headers['X-HELLO'] = 'hello' }.body + assert_equal 'b', @conn.get('/yo').body + end + + def test_middleware_allow_different_outcomes_for_the_same_request + @stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] } + @stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'world'] } + assert_equal 'hello', @conn.get("/hello").body + assert_equal 'world', @conn.get("/hello").body + end + + def test_yields_env_to_stubs + @stubs.get '/hello' do |env| + assert_equal '/hello', env[:url].path + assert_equal 'foo.com', env[:url].host + assert_equal '1', env[:params]['a'] + assert_equal 'text/plain', env[:request_headers]['Accept'] + [200, {}, 'a'] + end + + @conn.headers['Accept'] = 'text/plain' + assert_equal 'a', @conn.get('http://foo.com/hello?a=1').body + end + + def test_parses_params_with_default_encoder + @stubs.get '/hello' do |env| + assert_equal '1', env[:params]['a']['b'] + [200, {}, 'a'] + end + + assert_equal 'a', @conn.get('http://foo.com/hello?a[b]=1').body + end + + def test_parses_params_with_nested_encoder + @stubs.get '/hello' do |env| + assert_equal '1', env[:params]['a']['b'] + [200, {}, 'a'] + end + + @conn.options.params_encoder = Faraday::NestedParamsEncoder + assert_equal 'a', @conn.get('http://foo.com/hello?a[b]=1').body + end + + def test_parses_params_with_flat_encoder + @stubs.get '/hello' do |env| + assert_equal '1', env[:params]['a[b]'] + [200, {}, 'a'] + end + + @conn.options.params_encoder = Faraday::FlatParamsEncoder + assert_equal 'a', @conn.get('http://foo.com/hello?a[b]=1').body + end + + def test_raises_an_error_if_no_stub_is_found_for_request + assert_raises Stubs::NotFound do + @conn.get('/invalid'){ [200, {}, []] } + end + end + + def test_raises_an_error_if_no_stub_is_found_for_request_without_this_header + @stubs.get('/yo', { 'X-HELLO' => 'hello' }) { [200, {}, 'a'] } + assert_raises Faraday::Adapter::Test::Stubs::NotFound do + @conn.get('/yo') + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/adapters/typhoeus_test.rb b/.gems/gems/faraday-0.9.0/test/adapters/typhoeus_test.rb new file mode 100644 index 0000000..5ddc50b --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/adapters/typhoeus_test.rb @@ -0,0 +1,28 @@ +require File.expand_path('../integration', __FILE__) + +module Adapters + class TyphoeusTest < Faraday::TestCase + + def adapter() :typhoeus end + + Integration.apply(self, :Parallel) do + # https://github.com/dbalatero/typhoeus/issues/75 + undef :test_GET_with_body + + # Not a Typhoeus bug, but WEBrick inability to handle "100-continue" + # which libcurl seems to generate for this particular request: + undef :test_POST_sends_files + + # inconsistent outcomes ranging from successful response to connection error + undef :test_proxy_auth_fail if ssl_mode? + + def test_binds_local_socket + host = '1.2.3.4' + conn = create_connection :request => { :bind => { :host => host } } + assert_equal host, conn.options[:bind][:host] + end + + end unless jruby? + end +end + diff --git a/.gems/gems/faraday-0.9.0/test/authentication_middleware_test.rb b/.gems/gems/faraday-0.9.0/test/authentication_middleware_test.rb new file mode 100644 index 0000000..1fbad61 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/authentication_middleware_test.rb @@ -0,0 +1,65 @@ +require File.expand_path('../helper', __FILE__) + +class AuthenticationMiddlewareTest < Faraday::TestCase + def conn + Faraday::Connection.new('http://example.net/') do |builder| + yield(builder) + builder.adapter :test do |stub| + stub.get('/auth-echo') do |env| + [200, {}, env[:request_headers]['Authorization']] + end + end + end + end + + def test_basic_middleware_adds_basic_header + response = conn { |b| b.request :basic_auth, 'aladdin', 'opensesame' }.get('/auth-echo') + assert_equal 'Basic YWxhZGRpbjpvcGVuc2VzYW1l', response.body + end + + def test_basic_middleware_adds_basic_header_correctly_with_long_values + response = conn { |b| b.request :basic_auth, 'A' * 255, '' }.get('/auth-echo') + assert_equal "Basic #{'QUFB' * 85}Og==", response.body + end + + def test_basic_middleware_does_not_interfere_with_existing_authorization + response = conn { |b| b.request :basic_auth, 'aladdin', 'opensesame' }. + get('/auth-echo', nil, :authorization => 'Token token="bar"') + assert_equal 'Token token="bar"', response.body + end + + def test_token_middleware_adds_token_header + response = conn { |b| b.request :token_auth, 'quux' }.get('/auth-echo') + assert_equal 'Token token="quux"', response.body + end + + def test_token_middleware_includes_other_values_if_provided + response = conn { |b| + b.request :token_auth, 'baz', :foo => 42 + }.get('/auth-echo') + assert_match(/^Token /, response.body) + assert_match(/token="baz"/, response.body) + assert_match(/foo="42"/, response.body) + end + + def test_token_middleware_does_not_interfere_with_existing_authorization + response = conn { |b| b.request :token_auth, 'quux' }. + get('/auth-echo', nil, :authorization => 'Token token="bar"') + assert_equal 'Token token="bar"', response.body + end + + def test_authorization_middleware_with_string + response = conn { |b| + b.request :authorization, 'custom', 'abc def' + }.get('/auth-echo') + assert_match(/^custom abc def$/, response.body) + end + + def test_authorization_middleware_with_hash + response = conn { |b| + b.request :authorization, 'baz', :foo => 42 + }.get('/auth-echo') + assert_match(/^baz /, response.body) + assert_match(/foo="42"/, response.body) + end +end diff --git a/.gems/gems/faraday-0.9.0/test/composite_read_io_test.rb b/.gems/gems/faraday-0.9.0/test/composite_read_io_test.rb new file mode 100644 index 0000000..0632dee --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/composite_read_io_test.rb @@ -0,0 +1,111 @@ +require File.expand_path(File.join(File.dirname(__FILE__), 'helper')) +require 'stringio' + +class CompositeReadIOTest < Faraday::TestCase + Part = Struct.new(:to_io) do + def length() to_io.string.length end + end + + def part(str) + Part.new StringIO.new(str) + end + + def composite_io(*parts) + Faraday::CompositeReadIO.new(*parts) + end + + def test_empty + io = composite_io + assert_equal 0, io.length + assert_equal "", io.read + end + + def test_empty_returns_nil_for_limited_read + assert_nil composite_io.read(1) + end + + def test_empty_parts_returns_nil_for_limited_read + io = composite_io(part(""), part("")) + assert_nil io.read(1) + end + + def test_multipart_read_all + io = composite_io(part("abcd"), part("1234")) + assert_equal 8, io.length + assert_equal "abcd1234", io.read + end + + def test_multipart_read_limited + io = composite_io(part("abcd"), part("1234")) + assert_equal "abc", io.read(3) + assert_equal "d12", io.read(3) + assert_equal "34", io.read(3) + assert_equal nil, io.read(3) + assert_equal nil, io.read(3) + end + + def test_multipart_read_limited_size_larger_than_part + io = composite_io(part("abcd"), part("1234")) + assert_equal "abcd12", io.read(6) + assert_equal "34", io.read(6) + assert_equal nil, io.read(6) + end + + def test_multipart_read_with_blank_parts + io = composite_io(part(""), part("abcd"), part(""), part("1234"), part("")) + assert_equal "abcd12", io.read(6) + assert_equal "34", io.read(6) + assert_equal nil, io.read(6) + end + + def test_multipart_rewind + io = composite_io(part("abcd"), part("1234")) + assert_equal "abc", io.read(3) + assert_equal "d12", io.read(3) + io.rewind + assert_equal "abc", io.read(3) + assert_equal "d1234", io.read(5) + assert_equal nil, io.read(3) + io.rewind + assert_equal "ab", io.read(2) + end + + # JRuby enforces types to copy_stream to be String or IO + if IO.respond_to?(:copy_stream) && !jruby? + def test_compatible_with_copy_stream + target_io = StringIO.new + def target_io.ensure_open_and_writable + # Rubinius compatibility + end + io = composite_io(part("abcd"), part("1234")) + + Faraday::Timer.timeout(1) do + IO.copy_stream(io, target_io) + end + assert_equal "abcd1234", target_io.string + end + end + + unless RUBY_VERSION < '1.9' + def test_read_from_multibyte + File.open(File.dirname(__FILE__) + '/multibyte.txt') do |utf8| + io = composite_io(part("\x86"), Part.new(utf8)) + assert_equal bin("\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\n"), io.read + end + end + + def test_limited_from_multibyte + File.open(File.dirname(__FILE__) + '/multibyte.txt') do |utf8| + io = composite_io(part("\x86"), Part.new(utf8)) + assert_equal bin("\x86\xE3\x83"), io.read(3) + assert_equal bin("\x95\xE3\x82"), io.read(3) + assert_equal bin("\xA1\xE3\x82\xA4\xE3\x83\xAB\n"), io.read(8) + end + end + end + + def bin(str) + str.force_encoding("BINARY") if str.respond_to?(:force_encoding) + str + end +end diff --git a/.gems/gems/faraday-0.9.0/test/connection_test.rb b/.gems/gems/faraday-0.9.0/test/connection_test.rb new file mode 100644 index 0000000..e164736 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/connection_test.rb @@ -0,0 +1,522 @@ +require File.expand_path('../helper', __FILE__) + +class TestConnection < Faraday::TestCase + + def with_env(key, proxy) + old_value = ENV.fetch(key, false) + ENV[key] = proxy + begin + yield + ensure + if old_value == false + ENV.delete key + else + ENV[key] = old_value + end + end + end + + def test_initialize_parses_host_out_of_given_url + conn = Faraday::Connection.new "http://sushi.com" + assert_equal 'sushi.com', conn.host + end + + def test_initialize_inherits_default_port_out_of_given_url + conn = Faraday::Connection.new "http://sushi.com" + assert_equal 80, conn.port + end + + def test_initialize_parses_scheme_out_of_given_url + conn = Faraday::Connection.new "http://sushi.com" + assert_equal 'http', conn.scheme + end + + def test_initialize_parses_port_out_of_given_url + conn = Faraday::Connection.new "http://sushi.com:815" + assert_equal 815, conn.port + end + + def test_initialize_parses_nil_path_prefix_out_of_given_url + conn = Faraday::Connection.new "http://sushi.com" + assert_equal '/', conn.path_prefix + end + + def test_initialize_parses_path_prefix_out_of_given_url + conn = Faraday::Connection.new "http://sushi.com/fish" + assert_equal '/fish', conn.path_prefix + end + + def test_initialize_parses_path_prefix_out_of_given_url_option + conn = Faraday::Connection.new :url => "http://sushi.com/fish" + assert_equal '/fish', conn.path_prefix + end + + def test_initialize_stores_default_params_from_options + conn = Faraday::Connection.new :params => {:a => 1} + assert_equal({'a' => 1}, conn.params) + end + + def test_initialize_stores_default_params_from_uri + conn = Faraday::Connection.new "http://sushi.com/fish?a=1" + assert_equal({'a' => '1'}, conn.params) + end + + def test_initialize_stores_default_params_from_uri_and_options + conn = Faraday::Connection.new "http://sushi.com/fish?a=1&b=2", :params => {'a' => 3} + assert_equal({'a' => 3, 'b' => '2'}, conn.params) + end + + def test_initialize_stores_default_headers_from_options + conn = Faraday::Connection.new :headers => {:user_agent => 'Faraday'} + assert_equal 'Faraday', conn.headers['User-agent'] + end + + def test_basic_auth_sets_header + conn = Faraday::Connection.new + assert_nil conn.headers['Authorization'] + + conn.basic_auth 'Aladdin', 'open sesame' + assert auth = conn.headers['Authorization'] + assert_equal 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', auth + end + + def test_auto_parses_basic_auth_from_url_and_unescapes + conn = Faraday::Connection.new :url => "http://foo%40bar.com:pass%20word@sushi.com/fish" + assert auth = conn.headers['Authorization'] + assert_equal Faraday::Request::BasicAuthentication.header("foo@bar.com", "pass word"), auth + end + + def test_token_auth_sets_header + conn = Faraday::Connection.new + assert_nil conn.headers['Authorization'] + + conn.token_auth 'abcdef', :nonce => 'abc' + assert auth = conn.headers['Authorization'] + assert_match(/^Token /, auth) + assert_match(/token="abcdef"/, auth) + assert_match(/nonce="abc"/, auth) + end + + def test_build_exclusive_url_uses_connection_host_as_default_uri_host + conn = Faraday::Connection.new + conn.host = 'sushi.com' + uri = conn.build_exclusive_url("/sake.html") + assert_equal 'sushi.com', uri.host + end + + def test_build_exclusive_url_overrides_connection_port_for_absolute_urls + conn = Faraday::Connection.new + conn.port = 23 + uri = conn.build_exclusive_url("http://sushi.com") + assert_equal 80, uri.port + end + + def test_build_exclusive_url_uses_connection_scheme_as_default_uri_scheme + conn = Faraday::Connection.new 'http://sushi.com' + uri = conn.build_exclusive_url("/sake.html") + assert_equal 'http', uri.scheme + end + + def test_build_exclusive_url_uses_connection_path_prefix_to_customize_path + conn = Faraday::Connection.new + conn.path_prefix = '/fish' + uri = conn.build_exclusive_url("sake.html") + assert_equal '/fish/sake.html', uri.path + end + + def test_build_exclusive_url_uses_root_connection_path_prefix_to_customize_path + conn = Faraday::Connection.new + conn.path_prefix = '/' + uri = conn.build_exclusive_url("sake.html") + assert_equal '/sake.html', uri.path + end + + def test_build_exclusive_url_forces_connection_path_prefix_to_be_absolute + conn = Faraday::Connection.new + conn.path_prefix = 'fish' + uri = conn.build_exclusive_url("sake.html") + assert_equal '/fish/sake.html', uri.path + end + + def test_build_exclusive_url_ignores_connection_path_prefix_trailing_slash + conn = Faraday::Connection.new + conn.path_prefix = '/fish/' + uri = conn.build_exclusive_url("sake.html") + assert_equal '/fish/sake.html', uri.path + end + + def test_build_exclusive_url_allows_absolute_uri_to_ignore_connection_path_prefix + conn = Faraday::Connection.new + conn.path_prefix = '/fish' + uri = conn.build_exclusive_url("/sake.html") + assert_equal '/sake.html', uri.path + end + + def test_build_exclusive_url_parses_url_params_into_path + conn = Faraday::Connection.new + uri = conn.build_exclusive_url("http://sushi.com/sake.html") + assert_equal '/sake.html', uri.path + end + + def test_build_exclusive_url_doesnt_add_ending_slash_given_nil_url + conn = Faraday::Connection.new + conn.url_prefix = "http://sushi.com/nigiri" + uri = conn.build_exclusive_url + assert_equal "/nigiri", uri.path + end + + def test_build_exclusive_url_doesnt_add_ending_slash_given_empty_url + conn = Faraday::Connection.new + conn.url_prefix = "http://sushi.com/nigiri" + uri = conn.build_exclusive_url('') + assert_equal "/nigiri", uri.path + end + + def test_build_exclusive_url_doesnt_use_connection_params + conn = Faraday::Connection.new "http://sushi.com/nigiri" + conn.params = {:a => 1} + assert_equal "http://sushi.com/nigiri", conn.build_exclusive_url.to_s + end + + def test_build_exclusive_url_uses_argument_params + conn = Faraday::Connection.new "http://sushi.com/nigiri" + conn.params = {:a => 1} + params = Faraday::Utils::ParamsHash.new + params[:a] = 2 + url = conn.build_exclusive_url(nil, params) + assert_equal "http://sushi.com/nigiri?a=2", url.to_s + end + + def test_build_url_uses_params + conn = Faraday::Connection.new "http://sushi.com/nigiri" + conn.params = {:a => 1, :b => 1} + assert_equal "http://sushi.com/nigiri?a=1&b=1", conn.build_url.to_s + end + + def test_build_url_merges_params + conn = Faraday::Connection.new "http://sushi.com/nigiri" + conn.params = {:a => 1, :b => 1} + url = conn.build_url(nil, :b => 2, :c => 3) + assert_equal "http://sushi.com/nigiri?a=1&b=2&c=3", url.to_s + end + + def test_env_url_parses_url_params_into_query + uri = env_url("http://sushi.com/sake.html", 'a[b]' => '1 + 2') + assert_equal "a%5Bb%5D=1+%2B+2", uri.query + end + + def test_env_url_escapes_per_spec + uri = env_url('http:/', 'a' => '1+2 foo~bar.-baz') + assert_equal "a=1%2B2+foo~bar.-baz", uri.query + end + + def test_env_url_bracketizes_nested_params_in_query + url = env_url nil, 'a' => {'b' => 'c'} + assert_equal "a%5Bb%5D=c", url.query + end + + def test_env_url_bracketizes_repeated_params_in_query + uri = env_url("http://sushi.com/sake.html", 'a' => [1, 2]) + assert_equal "a%5B%5D=1&a%5B%5D=2", uri.query + end + + def test_env_url_without_braketizing_repeated_params_in_query + uri = env_url 'http://sushi.com', 'a' => [1, 2] do |conn| + conn.options.params_encoder = Faraday::FlatParamsEncoder + end + assert_equal "a=1&a=2", uri.query + end + + def test_build_exclusive_url_parses_url + conn = Faraday::Connection.new + uri = conn.build_exclusive_url("http://sushi.com/sake.html") + assert_equal "http", uri.scheme + assert_equal "sushi.com", uri.host + assert_equal '/sake.html', uri.path + end + + def test_build_exclusive_url_parses_url_and_changes_scheme + conn = Faraday::Connection.new :url => "http://sushi.com/sushi" + conn.scheme = 'https' + uri = conn.build_exclusive_url("sake.html") + assert_equal 'https://sushi.com/sushi/sake.html', uri.to_s + end + + def test_build_exclusive_url_joins_url_to_base_with_ending_slash + conn = Faraday::Connection.new :url => "http://sushi.com/sushi/" + uri = conn.build_exclusive_url("sake.html") + assert_equal 'http://sushi.com/sushi/sake.html', uri.to_s + end + + def test_build_exclusive_url_used_default_base_with_ending_slash + conn = Faraday::Connection.new :url => "http://sushi.com/sushi/" + uri = conn.build_exclusive_url + assert_equal 'http://sushi.com/sushi/', uri.to_s + end + + def test_build_exclusive_url_overrides_base + conn = Faraday::Connection.new :url => "http://sushi.com/sushi/" + uri = conn.build_exclusive_url('/sake/') + assert_equal 'http://sushi.com/sake/', uri.to_s + end + + def test_build_exclusive_url_handles_uri_instances + conn = Faraday::Connection.new + uri = conn.build_exclusive_url(URI('/sake.html')) + assert_equal '/sake.html', uri.path + end + + def test_proxy_accepts_string + with_env 'http_proxy', "http://duncan.proxy.com:80" do + conn = Faraday::Connection.new + conn.proxy 'http://proxy.com' + assert_equal 'proxy.com', conn.proxy.host + end + end + + def test_proxy_accepts_uri + with_env 'http_proxy', "http://duncan.proxy.com:80" do + conn = Faraday::Connection.new + conn.proxy URI.parse('http://proxy.com') + assert_equal 'proxy.com', conn.proxy.host + end + end + + def test_proxy_accepts_hash_with_string_uri + with_env 'http_proxy', "http://duncan.proxy.com:80" do + conn = Faraday::Connection.new + conn.proxy :uri => 'http://proxy.com', :user => 'rick' + assert_equal 'proxy.com', conn.proxy.host + assert_equal 'rick', conn.proxy.user + end + end + + def test_proxy_accepts_hash + with_env 'http_proxy', "http://duncan.proxy.com:80" do + conn = Faraday::Connection.new + conn.proxy :uri => URI.parse('http://proxy.com'), :user => 'rick' + assert_equal 'proxy.com', conn.proxy.host + assert_equal 'rick', conn.proxy.user + end + end + + def test_proxy_accepts_http_env + with_env 'http_proxy', "http://duncan.proxy.com:80" do + conn = Faraday::Connection.new + assert_equal 'duncan.proxy.com', conn.proxy.host + end + end + + def test_proxy_accepts_http_env_with_auth + with_env 'http_proxy', "http://a%40b:my%20pass@duncan.proxy.com:80" do + conn = Faraday::Connection.new + assert_equal 'a@b', conn.proxy.user + assert_equal 'my pass', conn.proxy.password + end + end + + def test_proxy_accepts_env_without_scheme + with_env 'http_proxy', "localhost:8888" do + uri = Faraday::Connection.new.proxy[:uri] + assert_equal 'localhost', uri.host + assert_equal 8888, uri.port + end + end + + def test_no_proxy_from_env + with_env 'http_proxy', nil do + conn = Faraday::Connection.new + assert_equal nil, conn.proxy + end + end + + def test_no_proxy_from_blank_env + with_env 'http_proxy', '' do + conn = Faraday::Connection.new + assert_equal nil, conn.proxy + end + end + + def test_proxy_doesnt_accept_uppercase_env + with_env 'HTTP_PROXY', "http://localhost:8888/" do + conn = Faraday::Connection.new + assert_nil conn.proxy + end + end + + def test_proxy_requires_uri + conn = Faraday::Connection.new + assert_raises ArgumentError do + conn.proxy :uri => :bad_uri, :user => 'rick' + end + end + + def test_dups_connection_object + conn = Faraday::Connection.new 'http://sushi.com/foo', + :ssl => { :verify => :none }, + :headers => {'content-type' => 'text/plain'}, + :params => {'a'=>'1'} + + other = conn.dup + + assert_equal conn.build_exclusive_url, other.build_exclusive_url + assert_equal 'text/plain', other.headers['content-type'] + assert_equal '1', other.params['a'] + + other.basic_auth('', '') + other.headers['content-length'] = 12 + other.params['b'] = '2' + + assert_equal 2, other.builder.handlers.size + assert_equal 2, conn.builder.handlers.size + assert !conn.headers.key?('content-length') + assert !conn.params.key?('b') + end + + def test_initialize_with_false_option + conn = Faraday::Connection.new :ssl => {:verify => false} + assert !conn.ssl.verify? + end + + def test_init_with_block + conn = Faraday::Connection.new { } + assert_equal 0, conn.builder.handlers.size + end + + def test_init_with_block_yields_connection + conn = Faraday::Connection.new(:params => {'a'=>'1'}) { |faraday| + faraday.adapter :net_http + faraday.url_prefix = 'http://sushi.com/omnom' + assert_equal '1', faraday.params['a'] + } + assert_equal 1, conn.builder.handlers.size + assert_equal '/omnom', conn.path_prefix + end + + def env_url(url, params) + conn = Faraday::Connection.new(url, :params => params) + yield(conn) if block_given? + req = conn.build_request(:get) + req.to_env(conn).url + end +end + +class TestRequestParams < Faraday::TestCase + def create_connection(*args) + @conn = Faraday::Connection.new(*args) do |conn| + yield(conn) if block_given? + class << conn.builder + undef app + def app() lambda { |env| env } end + end + end + end + + def assert_query_equal(expected, query) + assert_equal expected, query.split('&').sort + end + + def with_default_params_encoder(encoder) + old_encoder = Faraday::Utils.default_params_encoder + begin + Faraday::Utils.default_params_encoder = encoder + yield + ensure + Faraday::Utils.default_params_encoder = old_encoder + end + end + + def test_merges_connection_and_request_params + create_connection 'http://a.co/?token=abc', :params => {'format' => 'json'} + query = get '?page=1', :limit => 5 + assert_query_equal %w[format=json limit=5 page=1 token=abc], query + end + + def test_overrides_connection_params + create_connection 'http://a.co/?a=a&b=b&c=c', :params => {:a => 'A'} do |conn| + conn.params[:b] = 'B' + assert_equal 'c', conn.params[:c] + end + assert_query_equal %w[a=A b=B c=c], get + end + + def test_all_overrides_connection_params + create_connection 'http://a.co/?a=a', :params => {:c => 'c'} do |conn| + conn.params = {'b' => 'b'} + end + assert_query_equal %w[b=b], get + end + + def test_overrides_request_params + create_connection + query = get '?p=1&a=a', :p => 2 + assert_query_equal %w[a=a p=2], query + end + + def test_overrides_request_params_block + create_connection + query = get '?p=1&a=a', :p => 2 do |req| + req.params[:p] = 3 + end + assert_query_equal %w[a=a p=3], query + end + + def test_overrides_request_params_block_url + create_connection + query = get nil, :p => 2 do |req| + req.url '?p=1&a=a', 'p' => 3 + end + assert_query_equal %w[a=a p=3], query + end + + def test_overrides_all_request_params + create_connection :params => {:c => 'c'} + query = get '?p=1&a=a', :p => 2 do |req| + assert_equal 'a', req.params[:a] + assert_equal 'c', req.params['c'] + assert_equal 2, req.params['p'] + req.params = {:b => 'b'} + assert_equal 'b', req.params['b'] + end + assert_query_equal %w[b=b], query + end + + def test_array_params_in_url + with_default_params_encoder(nil) do + create_connection 'http://a.co/page1?color[]=red&color[]=blue' + query = get + assert_equal "color%5B%5D=red&color%5B%5D=blue", query + end + end + + def test_array_params_in_params + with_default_params_encoder(nil) do + create_connection 'http://a.co/page1', :params => {:color => ['red', 'blue']} + query = get + assert_equal "color%5B%5D=red&color%5B%5D=blue", query + end + end + + def test_array_params_in_url_with_flat_params + with_default_params_encoder(Faraday::FlatParamsEncoder) do + create_connection 'http://a.co/page1?color=red&color=blue' + query = get + assert_equal "color=red&color=blue", query + end + end + + def test_array_params_in_params_with_flat_params + with_default_params_encoder(Faraday::FlatParamsEncoder) do + create_connection 'http://a.co/page1', :params => {:color => ['red', 'blue']} + query = get + assert_equal "color=red&color=blue", query + end + end + + def get(*args) + env = @conn.get(*args) do |req| + yield(req) if block_given? + end + env[:url].query + end +end diff --git a/.gems/gems/faraday-0.9.0/test/env_test.rb b/.gems/gems/faraday-0.9.0/test/env_test.rb new file mode 100644 index 0000000..4cae21a --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/env_test.rb @@ -0,0 +1,210 @@ +require File.expand_path('../helper', __FILE__) + +class EnvTest < Faraday::TestCase + def setup + @conn = Faraday.new :url => 'http://sushi.com/api', + :headers => {'Mime-Version' => '1.0'}, + :request => {:oauth => {:consumer_key => 'anonymous'}} + + @conn.options.timeout = 3 + @conn.options.open_timeout = 5 + @conn.ssl.verify = false + @conn.proxy 'http://proxy.com' + end + + def test_request_create_stores_method + env = make_env(:get) + assert_equal :get, env.method + end + + def test_request_create_stores_uri + env = make_env do |req| + req.url 'foo.json', 'a' => 1 + end + assert_equal 'http://sushi.com/api/foo.json?a=1', env.url.to_s + end + + def test_request_create_stores_headers + env = make_env do |req| + req['Server'] = 'Faraday' + end + headers = env.request_headers + assert_equal '1.0', headers['mime-version'] + assert_equal 'Faraday', headers['server'] + end + + def test_request_create_stores_body + env = make_env do |req| + req.body = 'hi' + end + assert_equal 'hi', env.body + end + + def test_global_request_options + env = make_env + assert_equal 3, env.request.timeout + assert_equal 5, env.request.open_timeout + end + + def test_per_request_options + env = make_env do |req| + req.options.timeout = 10 + req.options.boundary = 'boo' + req.options.oauth[:consumer_secret] = 'xyz' + end + assert_equal 10, env.request.timeout + assert_equal 5, env.request.open_timeout + assert_equal 'boo', env.request.boundary + + oauth_expected = {:consumer_secret => 'xyz', :consumer_key => 'anonymous'} + assert_equal oauth_expected, env.request.oauth + end + + def test_request_create_stores_ssl_options + env = make_env + assert_equal false, env.ssl.verify + end + + def test_request_create_stores_proxy_options + env = make_env + assert_equal 'proxy.com', env.request.proxy.host + end + + private + + def make_env(method = :get, connection = @conn, &block) + request = connection.build_request(method, &block) + request.to_env(connection) + end +end + +class HeadersTest < Faraday::TestCase + def setup + @headers = Faraday::Utils::Headers.new + end + + def test_normalizes_different_capitalizations + @headers['Content-Type'] = 'application/json' + assert_equal ['Content-Type'], @headers.keys + assert_equal 'application/json', @headers['Content-Type'] + assert_equal 'application/json', @headers['CONTENT-TYPE'] + assert_equal 'application/json', @headers['content-type'] + assert @headers.include?('content-type') + + @headers['content-type'] = 'application/xml' + assert_equal ['Content-Type'], @headers.keys + assert_equal 'application/xml', @headers['Content-Type'] + assert_equal 'application/xml', @headers['CONTENT-TYPE'] + assert_equal 'application/xml', @headers['content-type'] + end + + def test_fetch_key + @headers['Content-Type'] = 'application/json' + block_called = false + assert_equal 'application/json', @headers.fetch('content-type') { block_called = true } + assert_equal 'application/json', @headers.fetch('Content-Type') + assert_equal 'application/json', @headers.fetch('CONTENT-TYPE') + assert_equal 'application/json', @headers.fetch(:content_type) + assert_equal false, block_called + + assert_equal 'default', @headers.fetch('invalid', 'default') + assert_equal false, @headers.fetch('invalid', false) + assert_nil @headers.fetch('invalid', nil) + + assert_equal 'Invalid key', @headers.fetch('Invalid') { |key| "#{key} key" } + + expected_error = defined?(KeyError) ? KeyError : IndexError + assert_raises(expected_error) { @headers.fetch('invalid') } + end + + def test_delete_key + @headers['Content-Type'] = 'application/json' + assert_equal 1, @headers.size + assert @headers.include?('content-type') + assert_equal 'application/json', @headers.delete('content-type') + assert_equal 0, @headers.size + assert !@headers.include?('content-type') + assert_equal nil, @headers.delete('content-type') + end + + def test_parse_response_headers_leaves_http_status_line_out + @headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n") + assert_equal %w(Content-Type), @headers.keys + end + + def test_parse_response_headers_parses_lower_cased_header_name_and_value + @headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n") + assert_equal 'text/html', @headers['content-type'] + end + + def test_parse_response_headers_parses_lower_cased_header_name_and_value_with_colon + @headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://sushi.com/\r\n\r\n") + assert_equal 'http://sushi.com/', @headers['location'] + end + + def test_parse_response_headers_parses_blank_lines + @headers.parse("HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n") + assert_equal 'text/html', @headers['content-type'] + end +end + +class ResponseTest < Faraday::TestCase + def setup + @env = Faraday::Env.from \ + :status => 404, :body => 'yikes', + :response_headers => {'Content-Type' => 'text/plain'} + @response = Faraday::Response.new @env + end + + def test_finished + assert @response.finished? + end + + def test_error_on_finish + assert_raises RuntimeError do + @response.finish({}) + end + end + + def test_not_success + assert !@response.success? + end + + def test_status + assert_equal 404, @response.status + end + + def test_body + assert_equal 'yikes', @response.body + end + + def test_headers + assert_equal 'text/plain', @response.headers['Content-Type'] + assert_equal 'text/plain', @response['content-type'] + end + + def test_apply_request + @response.apply_request :body => 'a=b', :method => :post + assert_equal 'yikes', @response.body + assert_equal :post, @response.env[:method] + end + + def test_marshal + @response = Faraday::Response.new + @response.on_complete { } + @response.finish @env.merge(:params => 'moo') + + loaded = Marshal.load Marshal.dump(@response) + assert_nil loaded.env[:params] + assert_equal %w[body response_headers status], loaded.env.keys.map { |k| k.to_s }.sort + end + + def test_hash + hash = @response.to_hash + assert_kind_of Hash, hash + assert_equal @env.to_hash, hash + assert_equal hash[:status], @response.status + assert_equal hash[:response_headers], @response.headers + assert_equal hash[:body], @response.body + end +end diff --git a/.gems/gems/faraday-0.9.0/test/helper.rb b/.gems/gems/faraday-0.9.0/test/helper.rb new file mode 100644 index 0000000..9d3dda8 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/helper.rb @@ -0,0 +1,81 @@ +require 'rubygems' # rubygems/version doesn't work by itself +require 'rubygems/version' # for simplecov-html +require 'simplecov' +require 'coveralls' + +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter +] +SimpleCov.start do + add_filter '/bundle/' +end + +gem 'minitest' if defined? Bundler +require 'minitest/autorun' + +if ENV['LEFTRIGHT'] + begin + require 'leftright' + rescue LoadError + puts "Run `gem install leftright` to install leftright." + end +end + +require File.expand_path('../../lib/faraday', __FILE__) + +require 'stringio' +require 'uri' + +module Faraday + module LiveServerConfig + def live_server=(value) + @@live_server = case value + when /^http/ + URI(value) + when /./ + URI('http://127.0.0.1:4567') + end + end + + def live_server? + defined? @@live_server + end + + # Returns an object that responds to `host` and `port`. + def live_server + live_server? and @@live_server + end + end + + class TestCase < MiniTest::Test + extend LiveServerConfig + self.live_server = ENV['LIVE'] + + def test_default + assert true + end unless defined? ::MiniTest + + def capture_warnings + old, $stderr = $stderr, StringIO.new + begin + yield + $stderr.string + ensure + $stderr = old + end + end + + def self.jruby? + defined? RUBY_ENGINE and 'jruby' == RUBY_ENGINE + end + + def self.rbx? + defined? RUBY_ENGINE and 'rbx' == RUBY_ENGINE + end + + def self.ssl_mode? + ENV['SSL'] == 'yes' + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/live_server.rb b/.gems/gems/faraday-0.9.0/test/live_server.rb new file mode 100644 index 0000000..c106b29 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/live_server.rb @@ -0,0 +1,67 @@ +require 'sinatra/base' + +module Faraday +class LiveServer < Sinatra::Base + set :environment, :test + disable :logging + disable :protection + + [:get, :post, :put, :patch, :delete, :options].each do |method| + send(method, '/echo') do + kind = request.request_method.downcase + out = kind.dup + out << ' ?' << request.GET.inspect if request.GET.any? + out << ' ' << request.POST.inspect if request.POST.any? + + content_type 'text/plain' + return out + end + end + + get '/echo_header' do + header = "HTTP_#{params[:name].tr('-', '_').upcase}" + request.env.fetch(header) { 'NONE' } + end + + post '/file' do + if params[:uploaded_file].respond_to? :each_key + "file %s %s %d" % [ + params[:uploaded_file][:filename], + params[:uploaded_file][:type], + params[:uploaded_file][:tempfile].size + ] + else + status 400 + end + end + + get '/multi' do + [200, { 'Set-Cookie' => 'one, two' }, ''] + end + + get '/who-am-i' do + request.env['REMOTE_ADDR'] + end + + get '/slow' do + sleep 10 + [200, {}, 'ok'] + end + + get '/204' do + status 204 # no content + end + + get '/ssl' do + request.secure?.to_s + end + + error do |e| + "#{e.class}\n#{e.to_s}\n#{e.backtrace.join("\n")}" + end +end +end + +if $0 == __FILE__ + Faraday::LiveServer.run! +end diff --git a/.gems/gems/faraday-0.9.0/test/middleware/instrumentation_test.rb b/.gems/gems/faraday-0.9.0/test/middleware/instrumentation_test.rb new file mode 100644 index 0000000..364f13c --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/middleware/instrumentation_test.rb @@ -0,0 +1,88 @@ +require File.expand_path("../../helper", __FILE__) + +module Middleware + class InstrumentationTest < Faraday::TestCase + def setup + @instrumenter = FakeInstrumenter.new + end + + def test_default_name + assert_equal 'request.faraday', options.name + end + + def test_default_instrumenter + begin + instrumenter = options.instrumenter + rescue NameError => err + assert_match 'ActiveSupport', err.to_s + else + assert_equal ActiveSupport::Notifications, instrumenter + end + end + + def test_name + assert_equal 'booya', options(:name => 'booya').name + end + + def test_instrumenter + assert_equal :boom, options(:instrumenter => :boom).instrumenter + end + + def test_instrumentation_with_default_name + assert_equal 0, @instrumenter.instrumentations.size + + faraday = conn + res = faraday.get '/' + assert_equal 'ok', res.body + + assert_equal 1, @instrumenter.instrumentations.size + name, env = @instrumenter.instrumentations.first + assert_equal 'request.faraday', name + assert_equal '/', env[:url].path + end + + def test_instrumentation + assert_equal 0, @instrumenter.instrumentations.size + + faraday = conn :name => 'booya' + res = faraday.get '/' + assert_equal 'ok', res.body + + assert_equal 1, @instrumenter.instrumentations.size + name, env = @instrumenter.instrumentations.first + assert_equal 'booya', name + assert_equal '/', env[:url].path + end + + class FakeInstrumenter + attr_reader :instrumentations + + def initialize + @instrumentations = [] + end + + def instrument(name, env) + @instrumentations << [name, env] + yield + end + end + + def options(hash = nil) + Faraday::Request::Instrumentation::Options.from hash + end + + def conn(hash = nil) + hash ||= {} + hash[:instrumenter] = @instrumenter + + Faraday.new do |f| + f.request :instrumentation, hash + f.adapter :test do |stub| + stub.get '/' do + [200, {}, 'ok'] + end + end + end + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/middleware/retry_test.rb b/.gems/gems/faraday-0.9.0/test/middleware/retry_test.rb new file mode 100644 index 0000000..7c5a119 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/middleware/retry_test.rb @@ -0,0 +1,109 @@ +require File.expand_path("../../helper", __FILE__) + +module Middleware + class RetryTest < Faraday::TestCase + def setup + @times_called = 0 + end + + def conn(*retry_args) + Faraday.new do |b| + b.request :retry, *retry_args + b.adapter :test do |stub| + stub.post('/unstable') { + @times_called += 1 + @explode.call @times_called + } + end + end + end + + def test_unhandled_error + @explode = lambda {|n| raise "boom!" } + assert_raises(RuntimeError) { conn.post("/unstable") } + assert_equal 1, @times_called + end + + def test_handled_error + @explode = lambda {|n| raise Errno::ETIMEDOUT } + assert_raises(Errno::ETIMEDOUT) { conn.post("/unstable") } + assert_equal 3, @times_called + end + + def test_legacy_max_retries + @explode = lambda {|n| raise Errno::ETIMEDOUT } + assert_raises(Errno::ETIMEDOUT) { conn(1).post("/unstable") } + assert_equal 2, @times_called + end + + def test_new_max_retries + @explode = lambda {|n| raise Errno::ETIMEDOUT } + assert_raises(Errno::ETIMEDOUT) { conn(:max => 3).post("/unstable") } + assert_equal 4, @times_called + end + + def test_interval + @explode = lambda {|n| raise Errno::ETIMEDOUT } + started = Time.now + assert_raises(Errno::ETIMEDOUT) { + conn(:max => 2, :interval => 0.1).post("/unstable") + } + assert_in_delta 0.2, Time.now - started, 0.04 + end + + def test_calls_sleep_amount + explode_app = MiniTest::Mock.new + explode_app.expect(:call, nil, [{:body=>nil}]) + def explode_app.call(env) + raise Errno::ETIMEDOUT + end + + retry_middleware = Faraday::Request::Retry.new(explode_app) + class << retry_middleware + attr_accessor :sleep_amount_retries + + def sleep_amount(retries) + self.sleep_amount_retries.delete(retries) + 0 + end + end + retry_middleware.sleep_amount_retries = [2, 1] + + assert_raises(Errno::ETIMEDOUT) { + retry_middleware.call({}) + } + + assert_empty retry_middleware.sleep_amount_retries + end + + def test_exponential_backoff + middleware = Faraday::Request::Retry.new(nil, :max => 5, :interval => 0.1, :backoff_factor => 2) + assert_equal middleware.sleep_amount(5), 0.1 + assert_equal middleware.sleep_amount(4), 0.2 + assert_equal middleware.sleep_amount(3), 0.4 + end + + def test_random_additional_interval_amount + middleware = Faraday::Request::Retry.new(nil, :max => 2, :interval => 0.1, :interval_randomness => 1.0) + sleep_amount = middleware.sleep_amount(2) + assert_operator sleep_amount, :>=, 0.1 + assert_operator sleep_amount, :<=, 0.2 + middleware = Faraday::Request::Retry.new(nil, :max => 2, :interval => 0.1, :interval_randomness => 0.5) + sleep_amount = middleware.sleep_amount(2) + assert_operator sleep_amount, :>=, 0.1 + assert_operator sleep_amount, :<=, 0.15 + middleware = Faraday::Request::Retry.new(nil, :max => 2, :interval => 0.1, :interval_randomness => 0.25) + sleep_amount = middleware.sleep_amount(2) + assert_operator sleep_amount, :>=, 0.1 + assert_operator sleep_amount, :<=, 0.125 + end + + def test_custom_exceptions + @explode = lambda {|n| raise "boom!" } + assert_raises(RuntimeError) { + conn(:exceptions => StandardError).post("/unstable") + } + assert_equal 3, @times_called + end + end +end diff --git a/.gems/gems/faraday-0.9.0/test/middleware_stack_test.rb b/.gems/gems/faraday-0.9.0/test/middleware_stack_test.rb new file mode 100644 index 0000000..2f0d0d3 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/middleware_stack_test.rb @@ -0,0 +1,173 @@ +require File.expand_path('../helper', __FILE__) + +class MiddlewareStackTest < Faraday::TestCase + # mock handler classes + class Handler < Struct.new(:app) + def call(env) + (env[:request_headers]['X-Middleware'] ||= '') << ":#{self.class.name.split('::').last}" + app.call(env) + end + end + class Apple < Handler; end + class Orange < Handler; end + class Banana < Handler; end + + class Broken < Faraday::Middleware + dependency 'zomg/i_dont/exist' + end + + def setup + @conn = Faraday::Connection.new + @builder = @conn.builder + end + + def test_sets_default_adapter_if_none_set + default_middleware = Faraday::Request.lookup_middleware :url_encoded + default_adapter_klass = Faraday::Adapter.lookup_middleware Faraday.default_adapter + assert @builder[0] == default_middleware + assert @builder[1] == default_adapter_klass + end + + def test_allows_rebuilding + build_stack Apple + build_stack Orange + assert_handlers %w[Orange] + end + + def test_allows_extending + build_stack Apple + @conn.use Orange + assert_handlers %w[Apple Orange] + end + + def test_builder_is_passed_to_new_faraday_connection + new_conn = Faraday::Connection.new :builder => @builder + assert_equal @builder, new_conn.builder + end + + def test_insert_before + build_stack Apple, Orange + @builder.insert_before Apple, Banana + assert_handlers %w[Banana Apple Orange] + end + + def test_insert_after + build_stack Apple, Orange + @builder.insert_after Apple, Banana + assert_handlers %w[Apple Banana Orange] + end + + def test_swap_handlers + build_stack Apple, Orange + @builder.swap Apple, Banana + assert_handlers %w[Banana Orange] + end + + def test_delete_handler + build_stack Apple, Orange + @builder.delete Apple + assert_handlers %w[Orange] + end + + def test_stack_is_locked_after_making_requests + build_stack Apple + assert !@builder.locked? + @conn.get('/') + assert @builder.locked? + + assert_raises Faraday::RackBuilder::StackLocked do + @conn.use Orange + end + end + + def test_duped_stack_is_unlocked + build_stack Apple + assert !@builder.locked? + @builder.lock! + assert @builder.locked? + + duped_connection = @conn.dup + assert_equal @builder, duped_connection.builder + assert !duped_connection.builder.locked? + end + + def test_handler_comparison + build_stack Apple + assert_equal @builder.handlers.first, Apple + assert_equal @builder.handlers[0,1], [Apple] + assert_equal @builder.handlers.first, Faraday::RackBuilder::Handler.new(Apple) + end + + def test_unregistered_symbol + err = assert_raises(Faraday::Error){ build_stack :apple } + assert_equal ":apple is not registered on Faraday::Middleware", err.message + end + + def test_registered_symbol + Faraday::Middleware.register_middleware :apple => Apple + begin + build_stack :apple + assert_handlers %w[Apple] + ensure + unregister_middleware Faraday::Middleware, :apple + end + end + + def test_registered_symbol_with_proc + Faraday::Middleware.register_middleware :apple => lambda { Apple } + begin + build_stack :apple + assert_handlers %w[Apple] + ensure + unregister_middleware Faraday::Middleware, :apple + end + end + + def test_registered_symbol_with_array + Faraday::Middleware.register_middleware File.expand_path("..", __FILE__), + :strawberry => [lambda { Strawberry }, 'strawberry'] + begin + build_stack :strawberry + assert_handlers %w[Strawberry] + ensure + unregister_middleware Faraday::Middleware, :strawberry + end + end + + def test_missing_dependencies + build_stack Broken + err = assert_raises RuntimeError do + @conn.get('/') + end + assert_match "missing dependency for MiddlewareStackTest::Broken: ", err.message + assert_match "zomg/i_dont/exist", err.message + end + + private + + # make a stack with test adapter that reflects the order of middleware + def build_stack(*handlers) + @builder.build do |b| + handlers.each { |handler| b.use(*handler) } + yield(b) if block_given? + + b.adapter :test do |stub| + stub.get '/' do |env| + # echo the "X-Middleware" request header in the body + [200, {}, env[:request_headers]['X-Middleware'].to_s] + end + end + end + end + + def assert_handlers(list) + echoed_list = @conn.get('/').body.to_s.split(':') + echoed_list.shift if echoed_list.first == '' + assert_equal list, echoed_list + end + + def unregister_middleware(component, key) + # TODO: unregister API? + component.instance_variable_get('@registered_middleware').delete(key) + end +end diff --git a/.gems/gems/faraday-0.9.0/test/multibyte.txt b/.gems/gems/faraday-0.9.0/test/multibyte.txt new file mode 100644 index 0000000..24a84b0 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/multibyte.txt @@ -0,0 +1 @@ +ファイル diff --git a/.gems/gems/faraday-0.9.0/test/options_test.rb b/.gems/gems/faraday-0.9.0/test/options_test.rb new file mode 100644 index 0000000..1cacdf6 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/options_test.rb @@ -0,0 +1,252 @@ +require File.expand_path('../helper', __FILE__) + +class OptionsTest < Faraday::TestCase + class SubOptions < Faraday::Options.new(:sub); end + class ParentOptions < Faraday::Options.new(:a, :b, :c) + options :c => SubOptions + end + + def test_clear + options = SubOptions.new(1) + assert !options.empty? + assert options.clear + assert options.empty? + end + + def test_empty + options = SubOptions.new + assert options.empty? + options.sub = 1 + assert !options.empty? + options.delete(:sub) + assert options.empty? + end + + def test_each_key + options = ParentOptions.new(1, 2, 3) + enum = options.each_key + assert_equal enum.next.to_sym, :a + assert_equal enum.next.to_sym, :b + assert_equal enum.next.to_sym, :c + end + + def test_key? + options = SubOptions.new + assert !options.key?(:sub) + options.sub = 1 + if RUBY_VERSION >= '1.9' + assert options.key?(:sub) + else + assert options.key?("sub") + end + end + + def test_each_value + options = ParentOptions.new(1, 2, 3) + enum = options.each_value + assert_equal enum.next, 1 + assert_equal enum.next, 2 + assert_equal enum.next, 3 + end + + def test_value? + options = SubOptions.new + assert !options.value?(1) + options.sub = 1 + assert options.value?(1) + end + + def test_request_proxy_setter + options = Faraday::RequestOptions.new + assert_nil options.proxy + + assert_raises NoMethodError do + options[:proxy] = {:booya => 1} + end + + options[:proxy] = {:user => 'user'} + assert_kind_of Faraday::ProxyOptions, options.proxy + assert_equal 'user', options.proxy.user + + options.proxy = nil + assert_nil options.proxy + end + + def test_proxy_options_from_string + options = Faraday::ProxyOptions.from 'http://user:pass@example.org' + assert_equal 'user', options.user + assert_equal 'pass', options.password + assert_kind_of URI, options.uri + assert_equal '', options.path + assert_equal 80, options.port + assert_equal 'example.org', options.host + assert_equal 'http', options.scheme + end + + def test_proxy_options_hash_access + proxy = Faraday::ProxyOptions.from 'http://a%40b:pw%20d@example.org' + assert_equal 'a@b', proxy[:user] + assert_equal 'a@b', proxy.user + assert_equal 'pw d', proxy[:password] + assert_equal 'pw d', proxy.password + end + + def test_proxy_options_no_auth + proxy = Faraday::ProxyOptions.from 'http://example.org' + assert_nil proxy.user + assert_nil proxy.password + end + + def test_from_options + options = ParentOptions.new(1) + + value = ParentOptions.from(options) + assert_equal 1, value.a + assert_nil value.b + end + + def test_from_options_with_sub_object + sub = SubOptions.new(1) + options = ParentOptions.from :a => 1, :c => sub + assert_kind_of ParentOptions, options + assert_equal 1, options.a + assert_nil options.b + assert_kind_of SubOptions, options.c + assert_equal 1, options.c.sub + end + + def test_from_hash + options = ParentOptions.from :a => 1 + assert_kind_of ParentOptions, options + assert_equal 1, options.a + assert_nil options.b + end + + def test_from_hash_with_sub_object + options = ParentOptions.from :a => 1, :c => {:sub => 1} + assert_kind_of ParentOptions, options + assert_equal 1, options.a + assert_nil options.b + assert_kind_of SubOptions, options.c + assert_equal 1, options.c.sub + end + + def test_inheritance + subclass = Class.new(ParentOptions) + options = subclass.from(:c => {:sub => 'hello'}) + assert_kind_of SubOptions, options.c + assert_equal 'hello', options.c.sub + end + + def test_from_deep_hash + hash = {:b => 1} + options = ParentOptions.from :a => hash + assert_equal 1, options.a[:b] + + hash[:b] = 2 + assert_equal 1, options.a[:b] + + options.a[:b] = 3 + assert_equal 2, hash[:b] + assert_equal 3, options.a[:b] + end + + def test_from_nil + options = ParentOptions.from(nil) + assert_kind_of ParentOptions, options + assert_nil options.a + assert_nil options.b + end + + def test_invalid_key + assert_raises NoMethodError do + ParentOptions.from :invalid => 1 + end + end + + def test_update + options = ParentOptions.new(1) + assert_equal 1, options.a + assert_nil options.b + + updated = options.update :a => 2, :b => 3 + assert_equal 2, options.a + assert_equal 3, options.b + assert_equal options, updated + end + + def test_delete + options = ParentOptions.new(1) + assert_equal 1, options.a + assert_equal 1, options.delete(:a) + assert_nil options.a + end + + def test_merge + options = ParentOptions.new(1) + assert_equal 1, options.a + assert_nil options.b + + dup = options.merge :a => 2, :b => 3 + assert_equal 2, dup.a + assert_equal 3, dup.b + assert_equal 1, options.a + assert_nil options.b + end + + def test_env_access_member + e = Faraday::Env.new + assert_nil e.method + e.method = :get + assert_equal :get, e.method + end + + def test_env_access_symbol_non_member + e = Faraday::Env.new + assert_nil e[:custom] + e[:custom] = :boom + assert_equal :boom, e[:custom] + end + + def test_env_access_string_non_member + e = Faraday::Env.new + assert_nil e["custom"] + e["custom"] = :boom + assert_equal :boom, e["custom"] + end + + def test_env_fetch_ignores_false + ssl = Faraday::SSLOptions.new + ssl.verify = false + assert !ssl.fetch(:verify, true) + end + + def test_fetch_grabs_value + opt = Faraday::SSLOptions.new + opt.verify = 1 + assert_equal 1, opt.fetch(:verify, false) { |k| :blah } + end + + def test_fetch_uses_falsey_default + opt = Faraday::SSLOptions.new + assert_equal false, opt.fetch(:verify, false) { |k| :blah } + end + + def test_fetch_accepts_block + opt = Faraday::SSLOptions.new + assert_equal "yo :verify", opt.fetch(:verify) { |k| "yo #{k.inspect}"} + end + + def test_fetch_needs_a_default_if_key_is_missing + opt = Faraday::SSLOptions.new + assert_raises Faraday::Options.fetch_error_class do + opt.fetch :verify + end + end + + def test_fetch_works_with_key + opt = Faraday::SSLOptions.new + opt.verify = 1 + assert_equal 1, opt.fetch(:verify) + end +end diff --git a/.gems/gems/faraday-0.9.0/test/request_middleware_test.rb b/.gems/gems/faraday-0.9.0/test/request_middleware_test.rb new file mode 100644 index 0000000..aca011f --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/request_middleware_test.rb @@ -0,0 +1,142 @@ +# encoding: utf-8 +require File.expand_path('../helper', __FILE__) + +Faraday::CompositeReadIO.class_eval { attr_reader :ios } + +class RequestMiddlewareTest < Faraday::TestCase + def setup + @conn = Faraday.new do |b| + b.request :multipart + b.request :url_encoded + b.adapter :test do |stub| + stub.post('/echo') do |env| + posted_as = env[:request_headers]['Content-Type'] + [200, {'Content-Type' => posted_as}, env[:body]] + end + end + end + end + + def with_utf8 + if defined?(RUBY_VERSION) && RUBY_VERSION.match(/1.8.\d/) + begin + previous_kcode = $KCODE + $KCODE = "UTF8" + yield + ensure + $KCODE = previous_kcode + end + else + yield + end + end + + def test_does_nothing_without_payload + response = @conn.post('/echo') + assert_nil response.headers['Content-Type'] + assert response.body.empty? + end + + def test_ignores_custom_content_type + response = @conn.post('/echo', { :some => 'data' }, 'content-type' => 'application/x-foo') + assert_equal 'application/x-foo', response.headers['Content-Type'] + assert_equal({ :some => 'data' }, response.body) + end + + def test_url_encoded_no_header + response = @conn.post('/echo', { :fruit => %w[apples oranges] }) + assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type'] + assert_equal 'fruit%5B%5D=apples&fruit%5B%5D=oranges', response.body + end + + def test_url_encoded_with_header + response = @conn.post('/echo', {'a'=>123}, 'content-type' => 'application/x-www-form-urlencoded') + assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type'] + assert_equal 'a=123', response.body + end + + def test_url_encoded_nested + response = @conn.post('/echo', { :user => {:name => 'Mislav', :web => 'mislav.net'} }) + assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type'] + expected = { 'user' => {'name' => 'Mislav', 'web' => 'mislav.net'} } + assert_equal expected, Faraday::Utils.parse_nested_query(response.body) + end + + def test_url_encoded_non_nested + response = @conn.post('/echo', { :dimensions => ['date', 'location']}) do |req| + req.options.params_encoder = Faraday::FlatParamsEncoder + end + assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type'] + expected = { 'dimensions' => ['date', 'location'] } + assert_equal expected, Faraday::Utils.parse_query(response.body) + assert_equal 'dimensions=date&dimensions=location', response.body + end + + def test_url_encoded_unicode + err = capture_warnings { + response = @conn.post('/echo', {:str => "eé cç aã aâ"}) + assert_equal "str=e%C3%A9+c%C3%A7+a%C3%A3+a%C3%A2", response.body + } + assert err.empty?, "stderr did include: #{err}" + end + + def test_url_encoded_unicode_with_kcode_set + with_utf8 do + err = capture_warnings { + response = @conn.post('/echo', {:str => "eé cç aã aâ"}) + assert_equal "str=e%C3%A9+c%C3%A7+a%C3%A3+a%C3%A2", response.body + } + assert err.empty?, "stderr did include: #{err}" + end + end + + def test_url_encoded_nested_keys + response = @conn.post('/echo', {'a'=>{'b'=>{'c'=>['d']}}}) + assert_equal "a%5Bb%5D%5Bc%5D%5B%5D=d", response.body + end + + def test_multipart + # assume params are out of order + regexes = [ + /name\=\"a\"/, + /name=\"b\[c\]\"\; filename\=\"request_middleware_test\.rb\"/, + /name=\"b\[d\]\"/] + + payload = {:a => 1, :b => {:c => Faraday::UploadIO.new(__FILE__, 'text/x-ruby'), :d => 2}} + response = @conn.post('/echo', payload) + + assert_kind_of Faraday::CompositeReadIO, response.body + assert_equal "multipart/form-data; boundary=%s" % Faraday::Request::Multipart::DEFAULT_BOUNDARY, + response.headers['Content-Type'] + + response.body.send(:ios).map{|io| io.read}.each do |io| + if re = regexes.detect { |r| io =~ r } + regexes.delete re + end + end + assert_equal [], regexes + end + + def test_multipart_with_arrays + # assume params are out of order + regexes = [ + /name\=\"a\"/, + /name=\"b\[\]\[c\]\"\; filename\=\"request_middleware_test\.rb\"/, + /name=\"b\[\]\[d\]\"/] + + payload = {:a => 1, :b =>[{:c => Faraday::UploadIO.new(__FILE__, 'text/x-ruby'), :d => 2}]} + response = @conn.post('/echo', payload) + + assert_kind_of Faraday::CompositeReadIO, response.body + assert_equal "multipart/form-data; boundary=%s" % Faraday::Request::Multipart::DEFAULT_BOUNDARY, + response.headers['Content-Type'] + + response.body.send(:ios).map{|io| io.read}.each do |io| + if re = regexes.detect { |r| io =~ r } + regexes.delete re + end + end + assert_equal [], regexes + end + +end diff --git a/.gems/gems/faraday-0.9.0/test/response_middleware_test.rb b/.gems/gems/faraday-0.9.0/test/response_middleware_test.rb new file mode 100644 index 0000000..ea8aba2 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/response_middleware_test.rb @@ -0,0 +1,72 @@ +require File.expand_path('../helper', __FILE__) + +class ResponseMiddlewareTest < Faraday::TestCase + def setup + @conn = Faraday.new do |b| + b.response :raise_error + b.adapter :test do |stub| + stub.get('ok') { [200, {'Content-Type' => 'text/html'}, ''] } + stub.get('not-found') { [404, {'X-Reason' => 'because'}, 'keep looking'] } + stub.get('error') { [500, {'X-Error' => 'bailout'}, 'fail'] } + end + end + end + + class ResponseUpcaser < Faraday::Response::Middleware + def parse(body) + body.upcase + end + end + + def test_success + assert @conn.get('ok') + end + + def test_raises_not_found + error = assert_raises Faraday::Error::ResourceNotFound do + @conn.get('not-found') + end + assert_equal 'the server responded with status 404', error.message + assert_equal 'because', error.response[:headers]['X-Reason'] + end + + def test_raises_error + error = assert_raises Faraday::Error::ClientError do + @conn.get('error') + end + assert_equal 'the server responded with status 500', error.message + assert_equal 'bailout', error.response[:headers]['X-Error'] + end + + def test_upcase + @conn.builder.insert(0, ResponseUpcaser) + assert_equal '', @conn.get('ok').body + end +end + +class ResponseNoBodyMiddleWareTest < Faraday::TestCase + def setup + @conn = Faraday.new do |b| + b.response :raise_error + b.adapter :test do |stub| + stub.get('not_modified') { [304, nil, nil] } + stub.get('no_content') { [204, nil, nil] } + end + end + @conn.builder.insert(0, NotCalled) + end + + class NotCalled < Faraday::Response::Middleware + def parse(body) + raise "this should not be called" + end + end + + def test_204 + assert_equal nil, @conn.get('no_content').body + end + + def test_304 + assert_equal nil, @conn.get('not_modified').body + end +end diff --git a/.gems/gems/faraday-0.9.0/test/strawberry.rb b/.gems/gems/faraday-0.9.0/test/strawberry.rb new file mode 100644 index 0000000..80c8d0b --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/strawberry.rb @@ -0,0 +1,2 @@ +class MiddlewareStackTest::Strawberry < MiddlewareStackTest::Handler +end diff --git a/.gems/gems/faraday-0.9.0/test/utils_test.rb b/.gems/gems/faraday-0.9.0/test/utils_test.rb new file mode 100644 index 0000000..b54f208 --- /dev/null +++ b/.gems/gems/faraday-0.9.0/test/utils_test.rb @@ -0,0 +1,58 @@ +require File.expand_path('../helper', __FILE__) + +class TestUtils < Faraday::TestCase + def setup + @url = "http://example.com/abc" + end + + # emulates ActiveSupport::SafeBuffer#gsub + FakeSafeBuffer = Struct.new(:string) do + def to_s() self end + def gsub(regex) + string.gsub(regex) { + match, = $&, '' =~ /a/ + yield(match) + } + end + end + + def test_escaping_safe_buffer + str = FakeSafeBuffer.new('$32,000.00') + assert_equal '%2432%2C000.00', Faraday::Utils.escape(str) + end + + def test_parses_with_default + with_default_uri_parser(nil) do + uri = normalize(@url) + assert_equal 'example.com', uri.host + end + end + + def test_parses_with_URI + with_default_uri_parser(::URI) do + uri = normalize(@url) + assert_equal 'example.com', uri.host + end + end + + def test_parses_with_block + with_default_uri_parser(lambda {|u| "booya#{"!" * u.size}" }) do + assert_equal 'booya!!!!!!!!!!!!!!!!!!!!!!', normalize(@url) + end + end + + def normalize(url) + Faraday::Utils::URI(url) + end + + def with_default_uri_parser(parser) + old_parser = Faraday::Utils.default_uri_parser + begin + Faraday::Utils.default_uri_parser = parser + yield + ensure + Faraday::Utils.default_uri_parser = old_parser + end + end +end + diff --git a/.gems/gems/http-0.6.2/.coveralls.yml b/.gems/gems/http-0.6.2/.coveralls.yml new file mode 100644 index 0000000..e1da6a3 --- /dev/null +++ b/.gems/gems/http-0.6.2/.coveralls.yml @@ -0,0 +1 @@ +service-name: travis-pro diff --git a/.gems/gems/http-0.6.2/.gitignore b/.gems/gems/http-0.6.2/.gitignore new file mode 100644 index 0000000..79ed009 --- /dev/null +++ b/.gems/gems/http-0.6.2/.gitignore @@ -0,0 +1,18 @@ +*.gem +.bundle +.config +.rvmrc +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc +lib/bundler/man +measurement +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp diff --git a/.gems/gems/http-0.6.2/.rspec b/.gems/gems/http-0.6.2/.rspec new file mode 100644 index 0000000..65d1e74 --- /dev/null +++ b/.gems/gems/http-0.6.2/.rspec @@ -0,0 +1,5 @@ +--backtrace +--color +--format=documentation +--order random +--warnings diff --git a/.gems/gems/http-0.6.2/.rubocop.yml b/.gems/gems/http-0.6.2/.rubocop.yml new file mode 100644 index 0000000..8aae49f --- /dev/null +++ b/.gems/gems/http-0.6.2/.rubocop.yml @@ -0,0 +1,116 @@ +AllCops: + Include: + - 'Gemfile' + - 'Rakefile' + - 'http.gemspec' + +# Avoid long parameter lists +ParameterLists: + Max: 3 + CountKeywordArgs: true + +MethodLength: + CountComments: false + Max: 31 # TODO: lower to 15 + +ClassLength: + CountComments: false + Max: 100 + +CyclomaticComplexity: + Max: 13 # TODO: lower to 6 + +# Avoid more than `Max` levels of nesting. +BlockNesting: + Max: 3 + +# Do not force public/protected/private keyword to be indented at the same +# level as the def keyword. My personal preference is to outdent these keywords +# because I think when scanning code it makes it easier to identify the +# sections of code and visually separate them. When the keyword is at the same +# level I think it sort of blends in with the def keywords and makes it harder +# to scan the code and see where the sections are. +AccessModifierIndentation: + Enabled: false + +# Limit line length +LineLength: + Enabled: false + +# Disable documentation checking until a class needs to be documented once +Documentation: + Enabled: false + +# Not all trivial readers/writers can be defined with attr_* methods +TrivialAccessors: + Enabled: false + +# Enforce Ruby 1.8-compatible hash syntax +HashSyntax: + EnforcedStyle: hash_rockets + +# No spaces inside hash literals +SpaceInsideHashLiteralBraces: + EnforcedStyle: no_space + +# Allow dots at the end of lines +DotPosition: + Enabled: false + +# Don't require magic comment at the top of every file +Encoding: + Enabled: false + +# Enforce outdenting of access modifiers (i.e. public, private, protected) +AccessModifierIndentation: + EnforcedStyle: outdent + +EmptyLinesAroundAccessModifier: + Enabled: true + +# Align ends correctly +EndAlignment: + AlignWith: variable + +# Indentation of when/else +CaseIndentation: + IndentWhenRelativeTo: end + IndentOneStep: false + +# Use the old lambda literal syntax +Lambda: + Enabled: false + +DoubleNegation: + Enabled: false + +PercentLiteralDelimiters: + PreferredDelimiters: + '%': () + '%i': () + '%q': () + '%Q': () + '%r': '{}' + '%s': () + '%w': '[]' + '%W': '[]' + '%x': () + +Semicolon: + Exclude: + - 'spec/support/' + +# Do not force first argument to be separated with exactly single space. +# My (ixti) personal preference is to align code in columns when it makes +# sense: +# +# module HTTP +# module MimeType +# class JSON < Adapter +# register_adapter 'application/json', JSON +# register_alias 'application/json', :json +# end +# end +# end +SingleSpaceBeforeFirstArg: + Enabled: false diff --git a/.gems/gems/http-0.6.2/.travis.yml b/.gems/gems/http-0.6.2/.travis.yml new file mode 100644 index 0000000..b24aba1 --- /dev/null +++ b/.gems/gems/http-0.6.2/.travis.yml @@ -0,0 +1,21 @@ +bundler_args: --without development +env: + global: + - JRUBY_OPTS="$JRUBY_OPTS --debug" +language: ruby +rvm: + - 1.8.7 + - 1.9.2 + - 1.9.3 + - 2.0.0 + - 2.1 + - jruby-18mode + - jruby-19mode + - jruby-head + - rbx-2 + - ruby-head +matrix: + allow_failures: + - rvm: jruby-head + - rvm: ruby-head + fast_finish: true diff --git a/.gems/gems/http-0.6.2/CHANGES.md b/.gems/gems/http-0.6.2/CHANGES.md new file mode 100644 index 0000000..d0f39e8 --- /dev/null +++ b/.gems/gems/http-0.6.2/CHANGES.md @@ -0,0 +1,132 @@ +0.6.2 (2014-08-06) +------------------ + +* Fix default Host header value. See #150. (@ixti) +* Deprecate BearerToken authorization header. (@ixti) +* Fix handling of chunked responses without Content-Length header. (@ixti) +* Rename `HTTP.with_follow` to `HTTP.follow` and mark former one as being + deprecated (@ixti) + +0.6.1 (2014-05-07) +------------------ + +* Fix request `Content-Length` calculation for Unicode (@challengeechallengee) +* Add `Response#flush` (@ixti) +* Fix `Response::Body#readpartial` default size (@hannesg, @ixti) +* Add missing `CRLF` for chunked bodies (@hannesg) +* Fix forgotten CGI require (@ixti) +* Improve README (@tarcieri) + +0.6.0 (2014-04-04) +------------------ + +* Rename `HTTP::Request#method` to `HTTP::Request#verb` (@krainboltgreene) +* Add `HTTP::ResponseBody` class (@tarcieri) +* Change API of response on `HTTP::Client.request` and "friends" (`#get`, `#post`, etc) (@tarcieri) +* Add `HTTP::Response#readpartial` (@tarcieri) +* Add `HTTP::Headers` class (@ixti) +* Fix and improve following redirects (@ixti) +* Add `HTTP::Request#redirect` (@ixti) +* Add `HTTP::Response#content_type` (@ixti) +* Add `HTTP::Response#mime_type` (@ixti) +* Add `HTTP::Response#charset` (@ixti) +* Improve error message upon invalid URI scheme (@ixti) +* Consolidate errors under common `HTTP::Error` namespace (@ixti) +* Add easy way of adding Authorization header (@ixti) +* Fix proxy support (@hundredwatt) +* Fix and improve query params handing (@jwinter) +* Change API of custom MIME type parsers (@ixti) +* Remove `HTTP::Chainable#with_response` (@ixti) +* Remove `HTTP::Response::BodyDelegator` (@ixti) +* Remove `HTTP::Response#parsed_body` (@ixti) +* Bump up input buffer from 4K to 16K (@tarcieri) + +``` ruby +# Main API change you will mention is that `request` method and it's +# syntax sugar helpers like `get`, `post`, etc. now returns Response +# object instead of BodyDelegator: + +response = HTTP.get "http://example.com" +raw_body = HTTP.get("http://example.com").to_s +parsed_body = HTTP.get("http://example.com/users.json").parse + +# Second major change in API is work with request/response headers +# It is now delegated to `HTTP::Headers` class, so you can check it's +# documentation for details, here we will only outline main difference. +# Duckface (`[]=`) does not appends headers anymore + +request[:content_type] = "text/plain" +request[:content_type] = "text/html" +request[:content_type] # => "text/html" + +# In order to add multiple header values, you should pass array: + +request[:cookie] = ["foo=bar", "woo=hoo"] +request[:cookie] # => ["foo=bar", "woo=hoo"] + +# or call `#add` on headers: + +request.headers.add :accept, "text/plain" +request.headers.add :accept, "text/html" +request[:accept] # => ["text/plain", "text/html"] + +# Also, you can now read body in chunks (stream): + +res = HTTP.get "http://example.com" +File.open "/tmp/dummy.bin", "wb" do |io| + while (chunk = res.readpartial) + io << chunk + end +end +``` + +[Changes discussion](https://github.com/tarcieri/http/issues/116) + +0.5.1 (2014-05-27) +------------------ + +* Backports redirector fixes from 0.6.0 (@ixti) +* EOL of 0.5.X branch. + +0.5.0 +----- +* Add query string support +* New response delegator allows HTTP.get(uri).response +* HTTP::Chainable#stream provides a shorter alias for + with_response(:object) +* Better string inspect for HTTP::Response +* Curb compatibility layer removed + +0.4.0 +----- +* Fix bug accessing https URLs +* Fix several instances of broken redirect handling +* Add default user agent +* Many additional minor bugfixes + +0.3.0 +----- +* New implementation based on tmm1's http_parser.rb instead of Net::HTTP +* Support for following redirects +* Support for request body through {:body => ...} option +* HTTP#with_response (through Chainable) + +0.2.0 +----- +* Request and response objects +* Callback system +* Internal refactoring ensuring true chainability +* Use the certified gem to ensure SSL certificate verification + +0.1.0 +----- +* Testing against WEBrick +* Curb compatibility (require 'http/compat/curb') + +0.0.1 +----- +* Initial half-baked release + +0.0.0 +----- +* Vapoware release to claim the "http" gem name >:D diff --git a/.gems/gems/http-0.6.2/Gemfile b/.gems/gems/http-0.6.2/Gemfile new file mode 100644 index 0000000..0cace9c --- /dev/null +++ b/.gems/gems/http-0.6.2/Gemfile @@ -0,0 +1,31 @@ +source 'http://rubygems.org' + +gem 'rake', '~> 10.1.1' +gem 'jruby-openssl' if defined? JRUBY_VERSION + +group :development do + gem 'pry' + platforms :ruby_19, :ruby_20 do + gem 'pry-debugger' + gem 'pry-stack_explorer' + end + platforms :ruby_19, :ruby_20, :ruby_21 do + gem 'celluloid-io' + gem 'guard-rspec' + end +end + +group :test do + gem 'backports' + gem 'coveralls' + gem 'json', '>= 1.8.1', :platforms => [:jruby, :rbx, :ruby_18, :ruby_19] + gem 'mime-types', '~> 1.25', :platforms => [:jruby, :ruby_18] + gem 'rest-client', '~> 1.6.0', :platforms => [:jruby, :ruby_18] + gem 'rspec', '~> 2.14' + gem 'rubocop', '~> 0.24.0', :platforms => [:ruby_19, :ruby_20, :ruby_21] + gem 'simplecov', '>= 0.9' + gem 'yardstick' +end + +# Specify your gem's dependencies in http.gemspec +gemspec diff --git a/.gems/gems/http-0.6.2/Guardfile b/.gems/gems/http-0.6.2/Guardfile new file mode 100644 index 0000000..2f00b11 --- /dev/null +++ b/.gems/gems/http-0.6.2/Guardfile @@ -0,0 +1,9 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard :rspec do + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { "spec" } +end + diff --git a/.gems/gems/http-0.6.2/LICENSE.txt b/.gems/gems/http-0.6.2/LICENSE.txt new file mode 100644 index 0000000..92021d1 --- /dev/null +++ b/.gems/gems/http-0.6.2/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2014 Tony Arcieri, Erik Michaels-Ober + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/http-0.6.2/README.md b/.gems/gems/http-0.6.2/README.md new file mode 100644 index 0000000..fac2090 --- /dev/null +++ b/.gems/gems/http-0.6.2/README.md @@ -0,0 +1,259 @@ +![The HTTP Gem](https://raw.github.com/tarcieri/http/master/logo.png) +============== +[![Gem Version](https://badge.fury.io/rb/http.png)](http://rubygems.org/gems/http) +[![Build Status](https://secure.travis-ci.org/tarcieri/http.png?branch=master)](http://travis-ci.org/tarcieri/http) +[![Code Climate](https://codeclimate.com/github/tarcieri/http.png)](https://codeclimate.com/github/tarcieri/http) +[![Coverage Status](https://coveralls.io/repos/tarcieri/http/badge.png?branch=master)](https://coveralls.io/r/tarcieri/http) + +SEO Note +-------- + +This Gem has the worst name in the history of SEO. But perhaps we can fix that if we +all refer to it as "The HTTP Gem", or even better, the "Ruby HTTP Gem". + +About +----- + +The HTTP Gem is an easy-to-use client library for making requests from Ruby. It uses +a simple method chaining system for building requests, similar to Python's [Requests] + +Under the hood, The HTTP Gem uses [http_parser.rb], a fast HTTP parsing native +extension based on the Node.js parser and a Java port thereof. + +[requests]: http://docs.python-requests.org/en/latest/ +[http_parser.rb]: https://github.com/tmm1/http_parser.rb + +Help and Discussion +------------------- + +If you need help or just want to talk about the Ruby HTTP Gem, [visit our Google +Group][googlegroup], or join by email by sending a message to: +[ruby-http-gem+subscribe@googlegroups.com][subscribe]. + +[googlegroup]: https://groups.google.com/forum/#!forum/ruby-http-gem +[subscribe]: mailto:ruby-http-gem+subscribe@googlegroups.com + +If you believe you've found a bug, please report it at: + +https://github.com/tarcieri/http/issues + +Installation +------------ + +Add this line to your application's Gemfile: + + gem 'http' + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install http + +Inside of your Ruby program do: + + require 'http' + +...to pull it in as a dependency. + +Documentation +------------- + +[Please see the HTTP Gem Wiki](https://github.com/tarcieri/http/wiki) +for more detailed documentation and usage notes. + +Basic Usage +----------- + +Here's some simple examples to get you started: + +### GET requests + +```ruby +>> HTTP.get("http://www.google.com").to_s +=> "> HTTP.get("http://www.google.com") +=> #"text/html; charset=UTF-8", "Date"=>"Fri, ...> + => #"text/html; ...> +``` + +We can also obtain an `HTTP::ResponseBody` object for this response: + +```ruby +>> HTTP.get("http://www.google.com").body + => # +``` + +The response body can be streamed with `HTTP::ResponseBody#readpartial`: + +```ruby +>> HTTP.get("http://www.google.com").body.readpartial + => " {:foo => "42"} +``` +Making GET requests with query string parameters is as simple. + +```ruby +HTTP.get "http://example.com/resource", :params => {:foo => "bar"} +``` + +Want to POST with a specific body, JSON for instance? + +```ruby +HTTP.post "http://example.com/resource", :json => { :foo => '42' } +``` + +It's easy! + + +### Proxy Support + +Making request behind proxy is as simple as making them directly. Just specify +hostname (or IP address) of your proxy server and it's port, and here you go: + +```ruby +HTTP.via("proxy-hostname.local", 8080) + .get "http://example.com/resource" +``` + +Proxy needs authentication? No problem: + +```ruby +HTTP.via("proxy-hostname.local", 8080, "username", "password") + .get "http://example.com/resource" +``` + + +### Adding Headers + +The HTTP gem uses the concept of chaining to simplify requests. Let's say +you want to get the latest commit of this library from Github in JSON format. +One way we could do this is by tacking a filename on the end of the URL: + +```ruby +HTTP.get "https://github.com/tarcieri/http/commit/HEAD.json" +``` + +The Github API happens to support this approach, but really this is a bit of a +hack that makes it easy for people typing URLs into the address bars of +browsers to perform the act of content negotiation. Since we have access to +the full, raw power of HTTP, we can perform content negotiation the way HTTP +intends us to, by using the Accept header: + +```ruby +HTTP.with_headers(:accept => 'application/json'). + get("https://github.com/tarcieri/http/commit/HEAD") +``` + +This requests JSON from Github. Github is smart enough to understand our +request and returns a response with Content-Type: application/json. If you +happen to have a library loaded which defines the JSON constant and implements +JSON.parse, the HTTP gem will attempt to parse the JSON response. + +Shorter aliases exists for HTTP.with_headers: + +```ruby +HTTP.with(:accept => 'application/json'). + get("https://github.com/tarcieri/http/commit/HEAD") + +HTTP[:accept => 'application/json']. + get("https://github.com/tarcieri/http/commit/HEAD") +``` + +### Content Negotiation + +As important a concept as content negotiation is to HTTP, it sure should be easy, +right? But usually it's not, and so we end up adding ".json" onto the ends of +our URLs because the existing mechanisms make it too hard. It should be easy: + +```ruby +HTTP.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD") +``` + +This adds the appropriate Accept header for retrieving a JSON response for the +given resource. + + +### Celluloid::IO Support + +The HTTP Gem makes it simple to make multiple concurrent HTTP requests from a +Celluloid::IO actor. Here's a parallel HTTP fetcher with the HTTP Gem and +Celluloid::IO: + +```ruby +require 'celluloid/io' +require 'http' + +class HttpFetcher + include Celluloid::IO + + def fetch(url) + HTTP.get(url, socket_class: Celluloid::IO::TCPSocket) + end +end +``` + +There's a little more to it, but that's the core idea! + +* [Full parallel HTTP fetcher example](https://github.com/tarcieri/http/wiki/Parallel-requests-with-Celluloid%3A%3AIO) +* See also: [Celluloid::IO](https://github.com/celluloid/celluloid-io) + + +Supported Ruby Versions +----------------------- + +This library aims to support and is [tested against][travis] the following Ruby +versions: + +* Ruby 1.8.7 +* Ruby 1.9.2 +* Ruby 1.9.3 +* Ruby 2.0.0 +* Ruby 2.1.0 + +If something doesn't work on one of these versions, it's a bug. + +This library may inadvertently work (or seem to work) on other Ruby versions, +however support will only be provided for the versions listed above. + +If you would like this library to support another Ruby version or +implementation, you may volunteer to be a maintainer. Being a maintainer +entails making sure all tests run and pass on that implementation. When +something breaks on your implementation, you will be responsible for providing +patches in a timely fashion. If critical issues for a particular implementation +exist at the time of a major release, support for that Ruby version may be +dropped. + +[travis]: http://travis-ci.org/tarcieri/http + + +Contributing to The HTTP Gem +---------------------------- + +* Fork the HTTP gem on github +* Make your changes and send me a pull request +* If we like them we'll merge them +* If we've accepted a patch, feel free to ask for commit access! + +Copyright +--------- + +Copyright (c) 2014 Tony Arcieri, Erik Michaels-Ober. See LICENSE.txt for further details. diff --git a/.gems/gems/http-0.6.2/Rakefile b/.gems/gems/http-0.6.2/Rakefile new file mode 100644 index 0000000..b68f88e --- /dev/null +++ b/.gems/gems/http-0.6.2/Rakefile @@ -0,0 +1,29 @@ +#!/usr/bin/env rake +require 'bundler/gem_tasks' + +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new + +task :test => :spec + +begin + require 'rubocop/rake_task' + RuboCop::RakeTask.new +rescue LoadError + task :rubocop do + $stderr.puts 'RuboCop is disabled' + end +end + +require 'yardstick/rake/measurement' +Yardstick::Rake::Measurement.new do |measurement| + measurement.output = 'measurement/report.txt' +end + +require 'yardstick/rake/verify' +Yardstick::Rake::Verify.new do |verify| + verify.require_exact_threshold = false + verify.threshold = 58 +end + +task :default => [:spec, :rubocop, :verify_measurements] diff --git a/.gems/gems/http-0.6.2/examples/parallel_requests_with_celluloid.rb b/.gems/gems/http-0.6.2/examples/parallel_requests_with_celluloid.rb new file mode 100755 index 0000000..f47e2ad --- /dev/null +++ b/.gems/gems/http-0.6.2/examples/parallel_requests_with_celluloid.rb @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby +# +# Example of using the HTTP Gem with Celluloid::IO +# Make sure to 'gem install celluloid-io' before running +# +# Run as: bundle exec examples/parallel_requests_with_celluloid.rb +# + +require 'celluloid/io' +require 'http' + +class HttpFetcher + include Celluloid::IO + + def fetch(url) + # Note: For SSL support specify: + # ssl_socket_class: Celluloid::IO::SSLSocket + HTTP.get(url, :socket_class => Celluloid::IO::TCPSocket) + end +end + +fetcher = HttpFetcher.new + +urls = %w[http://ruby-lang.org/ http://rubygems.org/ http://celluloid.io/] + +# Kick off a bunch of future calls to HttpFetcher to grab the URLs in parallel +futures = urls.map { |u| [u, fetcher.future.fetch(u)] } + +# Consume the results as they come in +futures.each do |url, future| + # Wait for HttpFetcher#fetch to complete for this request + response = future.value + puts "Got #{url}: #{response.inspect}" +end + +# Suppress Celluloid's shutdown messages +# Otherwise the example is a bit noisy :| +exit! diff --git a/.gems/gems/http-0.6.2/http.gemspec b/.gems/gems/http-0.6.2/http.gemspec new file mode 100644 index 0000000..b586e84 --- /dev/null +++ b/.gems/gems/http-0.6.2/http.gemspec @@ -0,0 +1,29 @@ +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'http/version' + +Gem::Specification.new do |gem| + gem.authors = %w[Tony Arcieri] + gem.email = %w[tony.arcieri@gmail.com] + + gem.description = <<-DESCRIPTION.strip.gsub(/\s+/, ' ') + An easy-to-use client library for making requests from Ruby. + It uses a simple method chaining system for building requests, + similar to Python's Requests. + DESCRIPTION + + gem.summary = 'HTTP should be easy' + gem.homepage = 'https://github.com/tarcieri/http' + gem.licenses = %w[MIT] + + gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } + gem.files = `git ls-files`.split("\n") + gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + gem.name = 'http' + gem.require_paths = %w[lib] + gem.version = HTTP::VERSION + + gem.add_runtime_dependency 'http_parser.rb', '~> 0.6.0' + + gem.add_development_dependency 'bundler', '~> 1.0' +end diff --git a/.gems/gems/http-0.6.2/lib/http.rb b/.gems/gems/http-0.6.2/lib/http.rb new file mode 100644 index 0000000..f4c8460 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http.rb @@ -0,0 +1,24 @@ +require 'http/parser' + +require 'http/errors' +require 'http/chainable' +require 'http/client' +require 'http/options' +require 'http/request' +require 'http/request/writer' +require 'http/response' +require 'http/response/body' +require 'http/response/parser' +require 'http/backports' + +# HTTP should be easy +module HTTP + extend Chainable + + class << self + # HTTP[:accept => 'text/html'].get(...) + alias_method :[], :with_headers + end +end + +Http = HTTP unless defined?(Http) diff --git a/.gems/gems/http-0.6.2/lib/http/authorization_header.rb b/.gems/gems/http-0.6.2/lib/http/authorization_header.rb new file mode 100644 index 0000000..d095b23 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/authorization_header.rb @@ -0,0 +1,37 @@ +module HTTP + # Authorization header value builders + module AuthorizationHeader + class << self + # Associate type with given builder. + # @param [#to_sym] type + # @param [Class] klass + # @return [void] + def register(type, klass) + builders[type.to_sym] = klass + end + + # Builds Authorization header value with associated builder. + # @param [#to_sym] type + # @param [Object] opts + # @return [String] + def build(type, opts) + klass = builders[type.to_sym] + + fail Error, "Unknown authorization type #{type}" unless klass + + klass.new opts + end + + private + + # :nodoc: + def builders + @builders ||= {} + end + end + end +end + +# built-in builders +require 'http/authorization_header/basic_auth' +require 'http/authorization_header/bearer_token' diff --git a/.gems/gems/http-0.6.2/lib/http/authorization_header/basic_auth.rb b/.gems/gems/http-0.6.2/lib/http/authorization_header/basic_auth.rb new file mode 100644 index 0000000..9f42eb7 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/authorization_header/basic_auth.rb @@ -0,0 +1,24 @@ +require 'base64' + +module HTTP + module AuthorizationHeader + # Basic authorization header builder + # @see http://tools.ietf.org/html/rfc2617 + class BasicAuth + # @param [#fetch] opts + # @option opts [#to_s] :user + # @option opts [#to_s] :pass + def initialize(opts) + @user = opts.fetch :user + @pass = opts.fetch :pass + end + + # :nodoc: + def to_s + 'Basic ' << Base64.strict_encode64("#{@user}:#{@pass}") + end + end + + register :basic, BasicAuth + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/authorization_header/bearer_token.rb b/.gems/gems/http-0.6.2/lib/http/authorization_header/bearer_token.rb new file mode 100644 index 0000000..ab5eed4 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/authorization_header/bearer_token.rb @@ -0,0 +1,28 @@ +require 'base64' + +module HTTP + module AuthorizationHeader + # OAuth2 Bearer token authorization header builder + # @see http://tools.ietf.org/html/rfc6750 + # + # @deprecated Will be remove in v0.7.0 + class BearerToken + # @param [#fetch] opts + # @option opts [#to_s] :token + # @option opts [Boolean] :encode (false) deprecated + def initialize(opts) + warn "#{Kernel.caller.first}: [DEPRECATION] BearerToken deprecated." + + @token = opts.fetch :token + @token = Base64.strict_encode64 @token if opts.fetch(:encode, false) + end + + # :nodoc: + def to_s + "Bearer #{@token}" + end + end + + register :bearer, BearerToken + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/backports.rb b/.gems/gems/http-0.6.2/lib/http/backports.rb new file mode 100644 index 0000000..2f61bb6 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/backports.rb @@ -0,0 +1,2 @@ +require 'http/backports/uri' if RUBY_VERSION < '1.9.3' +require 'http/backports/base64' if RUBY_VERSION < '1.9.0' diff --git a/.gems/gems/http-0.6.2/lib/http/backports/base64.rb b/.gems/gems/http-0.6.2/lib/http/backports/base64.rb new file mode 100644 index 0000000..5826bd2 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/backports/base64.rb @@ -0,0 +1,6 @@ +module Base64 + # :nodoc: + def self.strict_encode64(data) + encode64(data).gsub(/\n/, '') + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/backports/uri.rb b/.gems/gems/http-0.6.2/lib/http/backports/uri.rb new file mode 100644 index 0000000..9fca044 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/backports/uri.rb @@ -0,0 +1,131 @@ +# Taken from Ruby 1.9's uri/common.rb +# By Akira Yamada +# License: +# You can redistribute it and/or modify it under the same term as Ruby. + +require 'uri' + +# Backport Ruby 1.9's form encoding/decoding functionality +module URI + TBLENCWWWCOMP_ = {} # :nodoc: + 256.times do |i| + TBLENCWWWCOMP_[i.chr] = format('%%%02X', i) + end + TBLENCWWWCOMP_[' '] = '+' + TBLENCWWWCOMP_.freeze + TBLDECWWWCOMP_ = {} # :nodoc: + 256.times do |i| + h, l = i >> 4, i & 15 + TBLDECWWWCOMP_[format('%%%X%X', h, l)] = i.chr + TBLDECWWWCOMP_[format('%%%x%X', h, l)] = i.chr + TBLDECWWWCOMP_[format('%%%X%x', h, l)] = i.chr + TBLDECWWWCOMP_[format('%%%x%x', h, l)] = i.chr + end + TBLDECWWWCOMP_['+'] = ' ' + TBLDECWWWCOMP_.freeze + + # Encode given +str+ to URL-encoded form data. + # + # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP + # (ASCII space) to + and converts others to %XX. + # + # This is an implementation of + # http://www.w3.org/TR/html5/association-of-controls-and-forms.html#url-encoded-form-data + # + # See URI.decode_www_form_component, URI.encode_www_form + def self.encode_www_form_component(str) + str.to_s.gsub(/[^*\-.0-9A-Z_a-z]/) { |chr| TBLENCWWWCOMP_[chr] } + end + + # Decode given +str+ of URL-encoded form data. + # + # This decods + to SP. + # + # See URI.encode_www_form_component, URI.decode_www_form + def self.decode_www_form_component(str) + fail(ArgumentError, "invalid %-encoding (#{str})") unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str + str.gsub(/\+|%\h\h/) { |chr| TBLDECWWWCOMP_[chr] } + end + + # Generate URL-encoded form data from given +enum+. + # + # This generates application/x-www-form-urlencoded data defined in HTML5 + # from given an Enumerable object. + # + # This internally uses URI.encode_www_form_component(str). + # + # This method doesn't convert the encoding of given items, so convert them + # before call this method if you want to send data as other than original + # encoding or mixed encoding data. (Strings which are encoded in an HTML5 + # ASCII incompatible encoding are converted to UTF-8.) + # + # This method doesn't handle files. When you send a file, use + # multipart/form-data. + # + # This is an implementation of + # http://www.w3.org/TR/html5/forms.html#url-encoded-form-data + # + # URI.encode_www_form([["q", "ruby"], ["lang", "en"]]) + # #=> "q=ruby&lang=en" + # URI.encode_www_form("q" => "ruby", "lang" => "en") + # #=> "q=ruby&lang=en" + # URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en") + # #=> "q=ruby&q=perl&lang=en" + # URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]]) + # #=> "q=ruby&q=perl&lang=en" + # + # See URI.encode_www_form_component, URI.decode_www_form + def self.encode_www_form(enum) + enum.map do |k, v| + if v.nil? + encode_www_form_component(k) + elsif v.respond_to?(:to_ary) + v.to_ary.map do |w| + next unless w + + str = encode_www_form_component(k) + str << '=' + str << encode_www_form_component(w) + end.join('&') + else + str = encode_www_form_component(k) + str << '=' + str << encode_www_form_component(v) + end + end.join('&') + end + + WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc: + + # Decode URL-encoded form data from given +str+. + # + # This decodes application/x-www-form-urlencoded data + # and returns array of key-value array. + # This internally uses URI.decode_www_form_component. + # + # _charset_ hack is not supported now because the mapping from given charset + # to Ruby's encoding is not clear yet. + # see also http://www.w3.org/TR/html5/syntax.html#character-encodings-0 + # + # This refers http://www.w3.org/TR/html5/forms.html#url-encoded-form-data + # + # ary = URI.decode_www_form("a=1&a=2&b=3") + # p ary #=> [['a', '1'], ['a', '2'], ['b', '3']] + # p ary.assoc('a').last #=> '1' + # p ary.assoc('b').last #=> '3' + # p ary.rassoc('a').last #=> '2' + # p Hash[ary] # => {"a"=>"2", "b"=>"3"} + # + # See URI.decode_www_form_component, URI.encode_www_form + def self.decode_www_form(str) + return [] if str.empty? + unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str + fail(ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})") + end + ary = [] + $&.scan(/([^=;&]+)=([^;&]*)/) do + ary << [decode_www_form_component(Regexp.last_match[1]), decode_www_form_component(Regexp.last_match[2])] + end + ary + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/chainable.rb b/.gems/gems/http-0.6.2/lib/http/chainable.rb new file mode 100644 index 0000000..f223e67 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/chainable.rb @@ -0,0 +1,143 @@ +require 'http/authorization_header' + +module HTTP + module Chainable + # Request a get sans response body + def head(uri, options = {}) + request :head, uri, options + end + + # Get a resource + def get(uri, options = {}) + request :get, uri, options + end + + # Post to a resource + def post(uri, options = {}) + request :post, uri, options + end + + # Put to a resource + def put(uri, options = {}) + request :put, uri, options + end + + # Delete a resource + def delete(uri, options = {}) + request :delete, uri, options + end + + # Echo the request back to the client + def trace(uri, options = {}) + request :trace, uri, options + end + + # Return the methods supported on the given URI + def options(uri, options = {}) + request :options, uri, options + end + + # Convert to a transparent TCP/IP tunnel + def connect(uri, options = {}) + request :connect, uri, options + end + + # Apply partial modifications to a resource + def patch(uri, options = {}) + request :patch, uri, options + end + + # Make an HTTP request with the given verb + def request(verb, uri, options = {}) + branch(options).request verb, uri + end + + # Make a request through an HTTP proxy + def via(*proxy) + proxy_hash = {} + proxy_hash[:proxy_address] = proxy[0] if proxy[0].is_a?(String) + proxy_hash[:proxy_port] = proxy[1] if proxy[1].is_a?(Integer) + proxy_hash[:proxy_username] = proxy[2] if proxy[2].is_a?(String) + proxy_hash[:proxy_password] = proxy[3] if proxy[3].is_a?(String) + + if [2, 4].include?(proxy_hash.keys.size) + branch default_options.with_proxy(proxy_hash) + else + fail(RequestError, "invalid HTTP proxy: #{proxy_hash}") + end + end + alias_method :through, :via + + # Alias for with_response(:object) + def stream + with_response(:object) + end + + # Make client follow redirects. + # @param opts (see Redirector#initialize) + # @return [HTTP::Client] + def follow(opts = true) + branch default_options.with_follow opts + end + + # (see #follow) + # @deprecated + alias_method :with_follow, :follow + + # Make a request with the given headers + def with_headers(headers) + branch default_options.with_headers(headers) + end + alias_method :with, :with_headers + + # Accept the given MIME type(s) + def accept(type) + with :accept => MimeType.normalize(type) + end + + # Make a request with the given Authorization header + def auth(*args) + value = case args.count + when 1 then args.first + when 2 then AuthorizationHeader.build(*args) + else fail ArgumentError, "wrong number of arguments (#{args.count} for 1..2)" + end + + with :authorization => value.to_s + end + + def default_options + @default_options ||= HTTP::Options.new + end + + def default_options=(opts) + @default_options = HTTP::Options.new(opts) + end + + def default_headers + default_options.headers + end + + def default_headers=(headers) + @default_options = default_options.dup do |opts| + opts.headers = headers + end + end + + def default_callbacks + default_options.callbacks + end + + def default_callbacks=(callbacks) + @default_options = default_options.dup do |opts| + opts.callbacks = callbacks + end + end + + private + + def branch(options) + HTTP::Client.new(options) + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/client.rb b/.gems/gems/http-0.6.2/lib/http/client.rb new file mode 100644 index 0000000..e6e03a5 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/client.rb @@ -0,0 +1,137 @@ +require 'cgi' +require 'uri' +require 'http/options' +require 'http/redirector' + +module HTTP + # Clients make requests and receive responses + class Client + include Chainable + + # Input buffer size + BUFFER_SIZE = 16_384 + + attr_reader :default_options + + def initialize(default_options = {}) + @default_options = HTTP::Options.new(default_options) + @parser = HTTP::Response::Parser.new + @socket = nil + end + + # Make an HTTP request + def request(verb, uri, opts = {}) + opts = @default_options.merge(opts) + uri = make_request_uri(uri, opts) + headers = opts.headers + proxy = opts.proxy + body = make_request_body(opts, headers) + + req = HTTP::Request.new(verb, uri, headers, proxy, body) + res = perform req, opts + + if opts.follow + res = Redirector.new(opts.follow).perform req, res do |request| + perform request, opts + end + end + + res + end + + # Perform a single (no follow) HTTP request + def perform(req, options) + # finish previous response if client was re-used + # TODO: this is pretty wrong, as socket shoud be part of response + # connection, so that re-use of client will not break multiple + # chunked responses + finish_response + + uri = req.uri + + # TODO: keep-alive support + @socket = options[:socket_class].open(req.socket_host, req.socket_port) + @socket = start_tls(@socket, options) if uri.is_a?(URI::HTTPS) + + req.stream @socket + + begin + read_more BUFFER_SIZE until @parser.headers + rescue IOError, Errno::ECONNRESET, Errno::EPIPE => ex + raise IOError, "problem making HTTP request: #{ex}" + end + + body = Response::Body.new(self) + res = Response.new(@parser.status_code, @parser.http_version, @parser.headers, body, uri) + + finish_response if :head == req.verb + + res + end + + # Read a chunk of the body + def readpartial(size = BUFFER_SIZE) + return unless @socket + + read_more size + chunk = @parser.chunk + + finish_response if @parser.finished? + + chunk.to_s + end + + private + + # Initialize TLS connection + def start_tls(socket, options) + # TODO: abstract away SSLContexts so we can use other TLS libraries + context = options[:ssl_context] || OpenSSL::SSL::SSLContext.new + socket = options[:ssl_socket_class].new(socket, context) + + socket.connect + socket + end + + # Merges query params if needed + def make_request_uri(uri, options) + uri = URI uri.to_s unless uri.is_a? URI + + if options.params && !options.params.empty? + params = CGI.parse(uri.query.to_s).merge(options.params || {}) + uri.query = URI.encode_www_form params + end + + uri + end + + # Create the request body object to send + def make_request_body(opts, headers) + if opts.body + opts.body + elsif opts.form + headers['Content-Type'] ||= 'application/x-www-form-urlencoded' + URI.encode_www_form(opts.form) + elsif opts.json + headers['Content-Type'] ||= 'application/json' + MimeType[:json].encode opts.json + end + end + + # Callback for when we've reached the end of a response + def finish_response + @socket.close if @socket && !@socket.closed? + @parser.reset + + @socket = nil + end + + # Feeds some more data into parser + def read_more(size) + @parser << @socket.readpartial(size) unless @parser.finished? + true + rescue EOFError + false + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/content_type.rb b/.gems/gems/http-0.6.2/lib/http/content_type.rb new file mode 100644 index 0000000..1c45d32 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/content_type.rb @@ -0,0 +1,27 @@ +module HTTP + ContentType = Struct.new(:mime_type, :charset) do + MIME_TYPE_RE = %r{^([^/]+/[^;]+)(?:$|;)} + CHARSET_RE = /;\s*charset=([^;]+)/i + + class << self + # Parse string and return ContentType struct + def parse(str) + new mime_type(str), charset(str) + end + + private + + # :nodoc: + def mime_type(str) + md = str.to_s.match MIME_TYPE_RE + md && md[1].to_s.strip.downcase + end + + # :nodoc: + def charset(str) + md = str.to_s.match CHARSET_RE + md && md[1].to_s.strip.gsub(/^"|"$/, '') + end + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/errors.rb b/.gems/gems/http-0.6.2/lib/http/errors.rb new file mode 100644 index 0000000..18e0464 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/errors.rb @@ -0,0 +1,13 @@ +module HTTP + # Generic error + class Error < StandardError; end + + # Generic Request error + class RequestError < Error; end + + # Generic Response error + class ResponseError < Error; end + + # Request to do something when we're in the wrong state + class StateError < ResponseError; end +end diff --git a/.gems/gems/http-0.6.2/lib/http/headers.rb b/.gems/gems/http-0.6.2/lib/http/headers.rb new file mode 100644 index 0000000..4bba3b3 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/headers.rb @@ -0,0 +1,154 @@ +require 'forwardable' + +require 'http/headers/mixin' + +module HTTP + class Headers + extend Forwardable + include Enumerable + + # Matches HTTP header names when in "Canonical-Http-Format" + CANONICAL_HEADER = /^[A-Z][a-z]*(-[A-Z][a-z]*)*$/ + + # :nodoc: + def initialize + @pile = [] + end + + # Sets header + # + # @return [void] + def set(name, value) + delete(name) + add(name, value) + end + alias_method :[]=, :set + + # Removes header + # + # @return [void] + def delete(name) + name = canonicalize_header name.to_s + @pile.delete_if { |k, _| k == name } + end + + # Append header + # + # @return [void] + def add(name, value) + name = canonicalize_header name.to_s + Array(value).each { |v| @pile << [name, v] } + end + alias_method :append, :add + + # Return array of header values if any. + # + # @return [Array] + def get(name) + name = canonicalize_header name.to_s + @pile.select { |k, _| k == name }.map { |_, v| v } + end + + # Smart version of {#get} + # + # @return [NilClass] if header was not set + # @return [Object] if header has exactly one value + # @return [Array] if header has more than one value + def [](name) + values = get(name) + + case values.count + when 0 then nil + when 1 then values.first + else values + end + end + + # Converts headers into a Rack-compatible Hash + # + # @return [Hash] + def to_h + Hash[keys.map { |k| [k, self[k]] }] + end + + # Array of key/value pairs + # + # @return [Array<[String, String]>] + def to_a + @pile.map { |pair| pair.map(&:dup) } + end + + # :nodoc: + def inspect + "#<#{self.class} #{to_h.inspect}>" + end + + # List of header names + # + # @return [Array] + def keys + @pile.map { |k, _| k }.uniq + end + + # Compares headers to another Headers or Array of key/value pairs + # + # @return [Boolean] + def ==(other) + return false unless other.respond_to? :to_a + @pile == other.to_a + end + + def_delegators :@pile, :each, :empty?, :hash + + # :nodoc: + def initialize_copy(orig) + super + @pile = to_a + end + + # Merge in `other` headers + # + # @see #merge + # @return [void] + def merge!(other) + self.class.coerce(other).to_h.each { |name, values| set name, values } + end + + # Returns new Headers instance with `other` headers merged in. + # + # @see #merge! + # @return [Headers] + def merge(other) + dup.tap { |dupped| dupped.merge! other } + end + + # Initiates new Headers object from given object. + # + # @raise [Error] if given object can't be coerced + # @param [#to_hash, #to_h, #to_a] object + # @return [Headers] + def self.coerce(object) + unless object.is_a? self + object = case + when object.respond_to?(:to_hash) then object.to_hash + when object.respond_to?(:to_h) then object.to_h + when object.respond_to?(:to_a) then object.to_a + else fail Error, "Can't coerce #{object.inspect} to Headers" + end + end + + headers = new + object.each { |k, v| headers.add k, v } + headers + end + + private + + # Transform to canonical HTTP header capitalization + # @param [String] name + # @return [String] + def canonicalize_header(name) + name[CANONICAL_HEADER] || name.split(/[\-_]/).map(&:capitalize).join('-') + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/headers/mixin.rb b/.gems/gems/http-0.6.2/lib/http/headers/mixin.rb new file mode 100644 index 0000000..7ee0080 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/headers/mixin.rb @@ -0,0 +1,11 @@ +require 'forwardable' + +module HTTP + class Headers + module Mixin + extend Forwardable + attr_reader :headers + def_delegators :headers, :[], :[]= + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/mime_type.rb b/.gems/gems/http-0.6.2/lib/http/mime_type.rb new file mode 100644 index 0000000..826e222 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/mime_type.rb @@ -0,0 +1,76 @@ +module HTTP + # MIME type encode/decode adapters + module MimeType + class << self + # Associate MIME type with adapter + # + # @example + # + # module JsonAdapter + # class << self + # def encode(obj) + # # encode logic here + # end + # + # def decode(str) + # # decode logic here + # end + # end + # end + # + # HTTP::MimeType.register_adapter 'application/json', MyJsonAdapter + # + # @param [#to_s] type + # @param [#encode, #decode] adapter + # @return [void] + def register_adapter(type, adapter) + adapters[type.to_s] = adapter + end + + # Returns adapter associated with MIME type + # + # @param [#to_s] type + # @raise [Error] if no adapter found + # @return [Class] + def [](type) + adapters[normalize type] || fail(Error, "Unknown MIME type: #{type}") + end + + # Register a shortcut for MIME type + # + # @example + # + # HTTP::MimeType.register_alias 'application/json', :json + # + # @param [#to_s] type + # @param [#to_sym] shortcut + # @return [void] + def register_alias(type, shortcut) + aliases[shortcut.to_sym] = type.to_s + end + + # Resolves type by shortcut if possible + # + # @param [#to_s] type + # @return [String] + def normalize(type) + aliases.fetch type, type.to_s + end + + private + + # :nodoc: + def adapters + @adapters ||= {} + end + + # :nodoc: + def aliases + @aliases ||= {} + end + end + end +end + +# built-in mime types +require 'http/mime_type/json' diff --git a/.gems/gems/http-0.6.2/lib/http/mime_type/adapter.rb b/.gems/gems/http-0.6.2/lib/http/mime_type/adapter.rb new file mode 100644 index 0000000..ac45b48 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/mime_type/adapter.rb @@ -0,0 +1,24 @@ +require 'forwardable' +require 'singleton' + +module HTTP + module MimeType + # Base encode/decode MIME type adapter + class Adapter + include Singleton + + class << self + extend Forwardable + def_delegators :instance, :encode, :decode + end + + %w[encode decode].each do |operation| + class_eval <<-RUBY, __FILE__, __LINE__ + def #{operation}(*) + fail Error, "\#{self.class} does not supports ##{operation}" + end + RUBY + end + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/mime_type/json.rb b/.gems/gems/http-0.6.2/lib/http/mime_type/json.rb new file mode 100644 index 0000000..b2604e7 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/mime_type/json.rb @@ -0,0 +1,23 @@ +require 'json' +require 'http/mime_type/adapter' + +module HTTP + module MimeType + # JSON encode/decode MIME type adapter + class JSON < Adapter + # Encodes object to JSON + def encode(obj) + return obj.to_json if obj.respond_to?(:to_json) + ::JSON.dump obj + end + + # Decodes JSON + def decode(str) + ::JSON.load str + end + end + + register_adapter 'application/json', JSON + register_alias 'application/json', :json + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/options.rb b/.gems/gems/http-0.6.2/lib/http/options.rb new file mode 100644 index 0000000..ca8f955 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/options.rb @@ -0,0 +1,130 @@ +require 'http/headers' +require 'openssl' +require 'socket' + +module HTTP + class Options + # How to format the response [:object, :body, :parse_body] + attr_accessor :response + + # HTTP headers to include in the request + attr_accessor :headers + + # Query string params to add to the url + attr_accessor :params + + # Form data to embed in the request + attr_accessor :form + + # JSON data to embed in the request + attr_accessor :json + + # Explicit request body of the request + attr_accessor :body + + # HTTP proxy to route request + attr_accessor :proxy + + # Socket classes + attr_accessor :socket_class, :ssl_socket_class + + # SSL context + attr_accessor :ssl_context + + # Follow redirects + attr_accessor :follow + + protected :response=, :headers=, :proxy=, :params=, :form=, :json=, :follow= + + @default_socket_class = TCPSocket + @default_ssl_socket_class = OpenSSL::SSL::SSLSocket + + class << self + attr_accessor :default_socket_class, :default_ssl_socket_class + + def new(options = {}) + return options if options.is_a?(self) + super + end + end + + def initialize(options = {}) + @response = options[:response] || :auto + @proxy = options[:proxy] || {} + @body = options[:body] + @params = options[:params] + @form = options[:form] + @json = options[:json] + @follow = options[:follow] + + @headers = HTTP::Headers.coerce(options[:headers] || {}) + + @socket_class = options[:socket_class] || self.class.default_socket_class + @ssl_socket_class = options[:ssl_socket_class] || self.class.default_ssl_socket_class + @ssl_context = options[:ssl_context] + end + + def with_headers(headers) + dup do |opts| + opts.headers = self.headers.merge(headers) + end + end + + %w[proxy params form json body follow].each do |method_name| + class_eval <<-RUBY, __FILE__, __LINE__ + def with_#{method_name}(value) + dup { |opts| opts.#{method_name} = value } + end + RUBY + end + + def [](option) + send(option) rescue nil + end + + def merge(other) + h1, h2 = to_hash, other.to_hash + merged = h1.merge(h2) do |k, v1, v2| + case k + when :headers + v1.merge(v2) + else + v2 + end + end + + self.class.new(merged) + end + + def to_hash + # FIXME: hardcoding these fields blows! We should have a declarative + # way of specifying all the options fields, and ensure they *all* + # get serialized here, rather than manually having to add them each time + { + :response => response, + :headers => headers.to_h, + :proxy => proxy, + :params => params, + :form => form, + :json => json, + :body => body, + :follow => follow, + :socket_class => socket_class, + :ssl_socket_class => ssl_socket_class, + :ssl_context => ssl_context + } + end + + def dup + dupped = super + yield(dupped) if block_given? + dupped + end + + private + + def argument_error!(message) + fail(Error, message, caller[1..-1]) + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/redirector.rb b/.gems/gems/http-0.6.2/lib/http/redirector.rb new file mode 100644 index 0000000..7cb8f5e --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/redirector.rb @@ -0,0 +1,66 @@ +module HTTP + class Redirector + # Notifies that we reached max allowed redirect hops + class TooManyRedirectsError < ResponseError; end + + # Notifies that following redirects got into an endless loop + class EndlessRedirectError < TooManyRedirectsError; end + + # HTTP status codes which indicate redirects + REDIRECT_CODES = [300, 301, 302, 303, 307, 308].freeze + + # :nodoc: + def initialize(options = nil) + options = {:max_hops => 5} unless options.respond_to?(:fetch) + @max_hops = options.fetch(:max_hops, 5) + @max_hops = false if @max_hops && 1 > @max_hops.to_i + end + + # Follows redirects until non-redirect response found + def perform(request, response, &block) + reset(request, response) + follow(&block) + end + + private + + # Reset redirector state + def reset(request, response) + @request, @response = request, response + @visited = [] + end + + # Follow redirects + def follow + while REDIRECT_CODES.include?(@response.code) + @visited << @request.uri.to_s + + fail TooManyRedirectsError if too_many_hops? + fail EndlessRedirectError if endless_loop? + + uri = @response.headers['Location'] + fail StateError, 'no Location header in redirect' unless uri + + if 303 == @response.code + @request = @request.redirect uri, :get + else + @request = @request.redirect uri + end + + @response = yield @request + end + + @response + end + + # Check if we reached max amount of redirect hops + def too_many_hops? + @max_hops < @visited.count if @max_hops + end + + # Check if we got into an endless loop + def endless_loop? + 2 < @visited.count(@visited.last) + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/request.rb b/.gems/gems/http-0.6.2/lib/http/request.rb new file mode 100644 index 0000000..5fca9e1 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/request.rb @@ -0,0 +1,153 @@ +require 'http/errors' +require 'http/headers' +require 'http/request/writer' +require 'http/version' +require 'base64' +require 'uri' + +module HTTP + class Request + include HTTP::Headers::Mixin + + # The method given was not understood + class UnsupportedMethodError < RequestError; end + + # The scheme of given URI was not understood + class UnsupportedSchemeError < RequestError; end + + # Default User-Agent header value + USER_AGENT = "RubyHTTPGem/#{HTTP::VERSION}".freeze + + # RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1 + METHODS = [:options, :get, :head, :post, :put, :delete, :trace, :connect] + + # RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV + METHODS.concat [:propfind, :proppatch, :mkcol, :copy, :move, :lock, :unlock] + + # RFC 3648: WebDAV Ordered Collections Protocol + METHODS.concat [:orderpatch] + + # RFC 3744: WebDAV Access Control Protocol + METHODS.concat [:acl] + + # draft-dusseault-http-patch: PATCH Method for HTTP + METHODS.concat [:patch] + + # draft-reschke-webdav-search: WebDAV Search + METHODS.concat [:search] + + # Allowed schemes + SCHEMES = [:http, :https, :ws, :wss] + + # Default ports of supported schemes + PORTS = { + :http => 80, + :https => 443, + :ws => 80, + :wss => 443 + } + + # Method is given as a lowercase symbol e.g. :get, :post + attr_reader :verb + + # Scheme is normalized to be a lowercase symbol e.g. :http, :https + attr_reader :scheme + + # The following alias may be removed in three minor versions (0.8.0) or one + # major version (1.0.0) + alias_method :__method__, :method + + # The following method may be removed in two minor versions (0.7.0) or one + # major version (1.0.0) + def method(*) + warn "#{Kernel.caller.first}: [DEPRECATION] HTTP::Request#method is deprecated. Use #verb instead. For Object#method, use #__method__." + @verb + end + + # "Request URI" as per RFC 2616 + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html + attr_reader :uri + attr_reader :proxy, :body, :version + + # :nodoc: + def initialize(verb, uri, headers = {}, proxy = {}, body = nil, version = '1.1') # rubocop:disable ParameterLists + @verb = verb.to_s.downcase.to_sym + @uri = uri.is_a?(URI) ? uri : URI(uri.to_s) + @scheme = @uri.scheme.to_s.downcase.to_sym if @uri.scheme + + fail(UnsupportedMethodError, "unknown method: #{verb}") unless METHODS.include?(@verb) + fail(UnsupportedSchemeError, "unknown scheme: #{scheme}") unless SCHEMES.include?(@scheme) + + @proxy, @body, @version = proxy, body, version + + @headers = HTTP::Headers.coerce(headers || {}) + + @headers['Host'] ||= default_host + @headers['User-Agent'] ||= USER_AGENT + end + + # Returns new Request with updated uri + def redirect(uri, verb = @verb) + uri = @uri.merge uri.to_s + req = self.class.new(verb, uri, headers, proxy, body, version) + req['Host'] = req.uri.host + req + end + + # Stream the request to a socket + def stream(socket) + include_proxy_authorization_header if using_authenticated_proxy? + Request::Writer.new(socket, body, headers, request_header).stream + end + + # Is this request using a proxy? + def using_proxy? + proxy && proxy.keys.size >= 2 + end + + # Is this request using an authenticated proxy? + def using_authenticated_proxy? + proxy && proxy.keys.size == 4 + end + + # Compute and add the Proxy-Authorization header + def include_proxy_authorization_header + digest = Base64.encode64("#{proxy[:proxy_username]}:#{proxy[:proxy_password]}").chomp + headers['Proxy-Authorization'] = "Basic #{digest}" + end + + # Compute HTTP request header for direct or proxy request + def request_header + if using_proxy? + "#{verb.to_s.upcase} #{uri} HTTP/#{version}" + else + path = uri.query && !uri.query.empty? ? "#{uri.path}?#{uri.query}" : uri.path + path = '/' if path.empty? + "#{verb.to_s.upcase} #{path} HTTP/#{version}" + end + end + + # Host for tcp socket + def socket_host + using_proxy? ? proxy[:proxy_address] : uri.host + end + + # Port for tcp socket + def socket_port + using_proxy? ? proxy[:proxy_port] : uri.port + end + + private + + # Default host (with port if needed) header value. + # + # @return [String] + def default_host + if PORTS[@scheme] == @uri.port + @uri.host + else + "#{@uri.host}:#{@uri.port}" + end + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/request/writer.rb b/.gems/gems/http-0.6.2/lib/http/request/writer.rb new file mode 100644 index 0000000..f4044ce --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/request/writer.rb @@ -0,0 +1,84 @@ +module HTTP + class Request + class Writer + # CRLF is the universal HTTP delimiter + CRLF = "\r\n" + + # Types valid to be used as body source + VALID_BODY_TYPES = [String, NilClass, Enumerable] + + def initialize(socket, body, headers, headerstart) # rubocop:disable ParameterLists + @body = body + @socket = socket + @headers = headers + @request_header = [headerstart] + + validate_body_type! + end + + # Adds headers to the request header from the headers array + def add_headers + @headers.each do |field, value| + @request_header << "#{field}: #{value}" + end + end + + # Stream the request to a socket + def stream + send_request_header + send_request_body + end + + # Adds the headers to the header array for the given request body we are working + # with + def add_body_type_headers + if @body.is_a?(String) && !@headers['Content-Length'] + @request_header << "Content-Length: #{@body.bytesize}" + elsif @body.is_a?(Enumerable) + encoding = @headers['Transfer-Encoding'] + if encoding == 'chunked' + @request_header << 'Transfer-Encoding: chunked' + else + fail(RequestError, 'invalid transfer encoding') + end + end + end + + # Joins the headers specified in the request into a correctly formatted + # http request header string + def join_headers + # join the headers array with crlfs, stick two on the end because + # that ends the request header + @request_header.join(CRLF) + (CRLF) * 2 + end + + def send_request_header + add_headers + add_body_type_headers + header = join_headers + + @socket << header + end + + def send_request_body + if @body.is_a?(String) + @socket << @body + elsif @body.is_a?(Enumerable) + @body.each do |chunk| + @socket << chunk.bytesize.to_s(16) << CRLF + @socket << chunk << CRLF + end + + @socket << '0' << CRLF * 2 + end + end + + private + + def validate_body_type! + return if VALID_BODY_TYPES.any? { |type| @body.is_a? type } + fail RequestError, "body of wrong type: #{@body.class}" + end + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/response.rb b/.gems/gems/http-0.6.2/lib/http/response.rb new file mode 100644 index 0000000..41ee941 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/response.rb @@ -0,0 +1,137 @@ +require 'delegate' +require 'http/headers' +require 'http/content_type' +require 'http/mime_type' + +module HTTP + class Response + include HTTP::Headers::Mixin + + STATUS_CODES = { + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Reserved', + 307 => 'Temporary Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 418 => "I'm a Teapot", + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 426 => 'Upgrade Required', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 510 => 'Not Extended' + } + STATUS_CODES.freeze + + SYMBOL_TO_STATUS_CODE = Hash[STATUS_CODES.map { |code, msg| [msg.downcase.gsub(/\s|-/, '_').to_sym, code] }] + SYMBOL_TO_STATUS_CODE.freeze + + attr_reader :status + attr_reader :body + attr_reader :uri + + # Status aliases! TIMTOWTDI!!! (Want to be idiomatic? Just use status :) + alias_method :code, :status + alias_method :status_code, :status + + def initialize(status, version, headers, body, uri = nil) # rubocop:disable ParameterLists + @status, @version, @body, @uri = status, version, body, uri + @headers = HTTP::Headers.coerce(headers || {}) + end + + # Obtain the 'Reason-Phrase' for the response + def reason + STATUS_CODES[@status] + end + + # Returns an Array ala Rack: `[status, headers, body]` + def to_a + [status, headers.to_h, body.to_s] + end + + # Return the response body as a string + def to_s + body.to_s + end + alias_method :to_str, :to_s + + # Flushes body and returns self-reference + def flush + body.to_s + self + end + + # Parsed Content-Type header + # @return [HTTP::ContentType] + def content_type + @content_type ||= ContentType.parse headers['Content-Type'] + end + + # MIME type of response (if any) + # @return [String, nil] + def mime_type + @mime_type ||= content_type.mime_type + end + + # Charset of response (if any) + # @return [String, nil] + def charset + @charset ||= content_type.charset + end + + # Parse response body with corresponding MIME type adapter. + # + # @param [#to_s] as Parse as given MIME type + # instead of the one determined from headers + # @raise [Error] if adapter not found + # @return [Object] + def parse(as = nil) + MimeType[as || mime_type].decode to_s + end + + # Inspect a response + def inspect + "#<#{self.class}/#{@version} #{status} #{reason} headers=#{headers.inspect}>" + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/response/body.rb b/.gems/gems/http-0.6.2/lib/http/response/body.rb new file mode 100644 index 0000000..7bb30c9 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/response/body.rb @@ -0,0 +1,64 @@ +require 'forwardable' +require 'http/client' + +module HTTP + class Response + # A streamable response body, also easily converted into a string + class Body + extend Forwardable + include Enumerable + def_delegator :to_s, :empty? + + def initialize(client) + @client = client + @streaming = nil + @contents = nil + end + + # Read up to length bytes, but return any data that's available + # @see HTTP::Client#readpartial + def readpartial(*args) + stream! + @client.readpartial(*args) + end + + # Iterate over the body, allowing it to be enumerable + def each + while (chunk = readpartial) + yield chunk + end + end + + # Eagerly consume the entire body as a string + def to_s + return @contents if @contents + fail StateError, 'body is being streamed' unless @streaming.nil? + + begin + @streaming = false + @contents = '' + while (chunk = @client.readpartial) + @contents << chunk + end + rescue + @contents = nil + raise + end + + @contents + end + alias_method :to_str, :to_s + + # Assert that the body is actively being streamed + def stream! + fail StateError, 'body has already been consumed' if @streaming == false + @streaming = true + end + + # Easier to interpret string inspect + def inspect + "#<#{self.class}:#{object_id.to_s(16)} @streaming=#{!!@streaming}>" + end + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/response/parser.rb b/.gems/gems/http-0.6.2/lib/http/response/parser.rb new file mode 100644 index 0000000..67c3ec1 --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/response/parser.rb @@ -0,0 +1,66 @@ +module HTTP + class Response + class Parser + attr_reader :headers + + def initialize + @parser = HTTP::Parser.new(self) + reset + end + + def add(data) + @parser << data + end + alias_method :<<, :add + + def headers? + !!@headers + end + + def http_version + @parser.http_version.join('.') + end + + def status_code + @parser.status_code + end + + # + # HTTP::Parser callbacks + # + + def on_headers_complete(headers) + @headers = headers + end + + def on_body(chunk) + if @chunk + @chunk << chunk + else + @chunk = chunk + end + end + + def chunk + chunk, @chunk = @chunk, nil + chunk + end + + def on_message_complete + @finished = true + end + + def reset + @parser.reset! + + @finished = false + @headers = nil + @chunk = nil + end + + def finished? + @finished + end + end + end +end diff --git a/.gems/gems/http-0.6.2/lib/http/version.rb b/.gems/gems/http-0.6.2/lib/http/version.rb new file mode 100644 index 0000000..883c90a --- /dev/null +++ b/.gems/gems/http-0.6.2/lib/http/version.rb @@ -0,0 +1,3 @@ +module HTTP + VERSION = '0.6.2' +end diff --git a/.gems/gems/http-0.6.2/logo.png b/.gems/gems/http-0.6.2/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8316879effa6fc589f291960c81ad6832b039b46 GIT binary patch literal 29762 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 '[USER]' }.to raise_error + end + + it 'fails when :user is not given' do + expect { described_class.new :pass => '[PASS]' }.to raise_error + end + end + + describe '#to_s' do + let(:user) { 'foo' } + let(:pass) { 'bar' * 100 } + let(:user_n_pass) { user + ':' + pass } + let(:builder) { described_class.new :user => user, :pass => pass } + + subject { builder.to_s } + + it { should eq "Basic #{Base64.strict_encode64 user_n_pass}" } + it { should match(/^Basic [^\s]+$/) } + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/authorization_header/bearer_token_spec.rb b/.gems/gems/http-0.6.2/spec/http/authorization_header/bearer_token_spec.rb new file mode 100644 index 0000000..02bf75f --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/authorization_header/bearer_token_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe HTTP::AuthorizationHeader::BearerToken do + describe '.new' do + it 'fails when options is not a Hash' do + expect { described_class.new '[TOKEN]' }.to raise_error + end + + it 'fails when :token is not given' do + expect { described_class.new :encode => true }.to raise_error + end + end + + describe '#to_s' do + let(:token) { 'foobar' * 100 } + let(:builder) { described_class.new options.merge :token => token } + + subject { builder.to_s } + + context 'when :encode => true' do + let(:options) { {:encode => true} } + it { should eq "Bearer #{Base64.strict_encode64 token}" } + it { should match(/^Bearer [^\s]+$/) } + end + + context 'when :encode => false' do + let(:options) { {:encode => false} } + it { should eq "Bearer #{token}" } + end + + context 'when :encode not specified' do + let(:options) { {} } + it { should eq "Bearer #{token}" } + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/authorization_header_spec.rb b/.gems/gems/http-0.6.2/spec/http/authorization_header_spec.rb new file mode 100644 index 0000000..b91bf44 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/authorization_header_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe HTTP::AuthorizationHeader do + describe '.build' do + context 'with unkown type' do + let(:type) { :foobar } + let(:opts) { {:foo => :bar} } + + it 'fails' do + expect { described_class.build type, opts }.to raise_error + end + end + + context 'with :basic type' do + let(:type) { :basic } + let(:opts) { {:user => 'user', :pass => 'pass'} } + + it 'passes options to BasicAuth' do + expect(described_class::BasicAuth).to receive(:new).with(opts) + described_class.build type, opts + end + end + + context 'with :bearer type' do + let(:type) { :bearer } + let(:opts) { {:token => 'token', :encode => true} } + + it 'passes options to BearerToken' do + expect(described_class::BearerToken).to receive(:new).with(opts) + described_class.build type, opts + end + end + end + + describe '.register' do + it 'registers given klass in builders registry' do + described_class.register :dummy, Class.new { def initialize(*); end } + expect { described_class.build(:dummy, 'foobar') }.to_not raise_error + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/backports/base64_spec.rb b/.gems/gems/http-0.6.2/spec/http/backports/base64_spec.rb new file mode 100644 index 0000000..77d4968 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/backports/base64_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +describe Base64 do + specify { expect(Base64).to respond_to :strict_encode64 } + + describe '.strict_encode64' do + let(:long_string) { (0...256).map { ('a'..'z').to_a[rand(26)] }.join } + + it 'returns a String without whitespaces' do + expect(Base64.strict_encode64 long_string).to_not match(/\s/) + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/backports/uri_spec.rb b/.gems/gems/http-0.6.2/spec/http/backports/uri_spec.rb new file mode 100644 index 0000000..a295cf2 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/backports/uri_spec.rb @@ -0,0 +1,9 @@ +require 'spec_helper' + +describe URI do + describe '.encode_www_form' do + it 'properly encodes arrays' do + expect(URI.encode_www_form :a => [:b, :c]).to eq 'a=b&a=c' + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/client_spec.rb b/.gems/gems/http-0.6.2/spec/http/client_spec.rb new file mode 100644 index 0000000..814e833 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/client_spec.rb @@ -0,0 +1,202 @@ +require 'spec_helper' + +describe HTTP::Client do + StubbedClient = Class.new(HTTP::Client) do + def perform(request, options) + stubs.fetch(request.uri.to_s) { super(request, options) } + end + + def stubs + @stubs ||= {} + end + + def stub(stubs) + @stubs = stubs + self + end + end + + def redirect_response(location, status = 302) + HTTP::Response.new(status, '1.1', {'Location' => location}, '') + end + + def simple_response(body, status = 200) + HTTP::Response.new(status, '1.1', {}, body) + end + + describe 'following redirects' do + it 'returns response of new location' do + client = StubbedClient.new(:follow => true).stub( + 'http://example.com/' => redirect_response('http://example.com/blog'), + 'http://example.com/blog' => simple_response('OK') + ) + + expect(client.get('http://example.com/').to_s).to eq 'OK' + end + + it 'prepends previous request uri scheme and host if needed' do + client = StubbedClient.new(:follow => true).stub( + 'http://example.com/' => redirect_response('/index'), + 'http://example.com/index' => redirect_response('/index.html'), + 'http://example.com/index.html' => simple_response('OK') + ) + + expect(client.get('http://example.com/').to_s).to eq 'OK' + end + + it 'fails upon endless redirects' do + client = StubbedClient.new(:follow => true).stub( + 'http://example.com/' => redirect_response('/') + ) + + expect { client.get('http://example.com/') } \ + .to raise_error(HTTP::Redirector::EndlessRedirectError) + end + + it 'fails if max amount of hops reached' do + client = StubbedClient.new(:follow => 5).stub( + 'http://example.com/' => redirect_response('/1'), + 'http://example.com/1' => redirect_response('/2'), + 'http://example.com/2' => redirect_response('/3'), + 'http://example.com/3' => redirect_response('/4'), + 'http://example.com/4' => redirect_response('/5'), + 'http://example.com/5' => redirect_response('/6'), + 'http://example.com/6' => simple_response('OK') + ) + + expect { client.get('http://example.com/') } \ + .to raise_error(HTTP::Redirector::TooManyRedirectsError) + end + end + + describe 'parsing params' do + let(:client) { HTTP::Client.new } + before { allow(client).to receive :perform } + + it 'accepts params within the provided URL' do + expect(HTTP::Request).to receive(:new) do |_, uri| + expect(CGI.parse uri.query).to eq('foo' => %w[bar]) + end + + client.get('http://example.com/?foo=bar') + end + + it 'combines GET params from the URI with the passed in params' do + expect(HTTP::Request).to receive(:new) do |_, uri| + expect(CGI.parse uri.query).to eq('foo' => %w[bar], 'baz' => %w[quux]) + end + + client.get('http://example.com/?foo=bar', :params => {:baz => 'quux'}) + end + + it 'merges duplicate values' do + expect(HTTP::Request).to receive(:new) do |_, uri| + expect(uri.query).to match(/^(a=1&a=2|a=2&a=1)$/) + end + + client.get('http://example.com/?a=1', :params => {:a => 2}) + end + + it 'does not modifies query part if no params were given' do + expect(HTTP::Request).to receive(:new) do |_, uri| + expect(uri.query).to eq 'deadbeef' + end + + client.get('http://example.com/?deadbeef') + end + + it 'does not corrupts index-less arrays' do + expect(HTTP::Request).to receive(:new) do |_, uri| + expect(CGI.parse uri.query).to eq 'a[]' => %w[b c], 'd' => %w[e] + end + + client.get('http://example.com/?a[]=b&a[]=c', :params => {:d => 'e'}) + end + end + + describe 'passing json' do + it 'encodes given object' do + client = HTTP::Client.new + allow(client).to receive(:perform) + + expect(HTTP::Request).to receive(:new) do |*args| + expect(args.last).to eq('{"foo":"bar"}') + end + + client.get('http://example.com/', :json => {:foo => :bar}) + end + end + + describe '#request' do + context 'with explicitly given `Host` header' do + let(:headers) { {'Host' => 'another.example.com'} } + let(:client) { described_class.new :headers => headers } + + it 'keeps `Host` header as is' do + expect(client).to receive(:perform) do |req, _| + expect(req['Host']).to eq 'another.example.com' + end + + client.request(:get, 'http://example.com/') + end + end + end + + describe '#perform' do + let(:client) { described_class.new } + + it 'calls finish_response before actual performance' do + TCPSocket.stub(:open) { throw :halt } + expect(client).to receive(:finish_response) + catch(:halt) { client.head "http://127.0.0.1:#{ExampleService::PORT}/" } + end + + it 'calls finish_response once body was fully flushed' do + expect(client).to receive(:finish_response).twice.and_call_original + client.get("http://127.0.0.1:#{ExampleService::PORT}/").to_s + end + + context 'with HEAD request' do + it 'does not iterates through body' do + expect(client).to_not receive(:readpartial) + client.head("http://127.0.0.1:#{ExampleService::PORT}/") + end + + it 'finishes response after headers were received' do + expect(client).to receive(:finish_response).twice.and_call_original + client.head("http://127.0.0.1:#{ExampleService::PORT}/") + end + end + + context 'when server fully flushes response in one chunk' do + before do + socket_spy = double + + chunks = [ + <<-RESPONSE.gsub(/^\s*\| */, '').gsub(/\n/, "\r\n") + | HTTP/1.1 200 OK + | Content-Type: text/html + | Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-11-22) + | Date: Mon, 24 Mar 2014 00:32:22 GMT + | Content-Length: 15 + | Connection: Keep-Alive + | + | + RESPONSE + ] + + socket_spy.stub(:close) { nil } + socket_spy.stub(:closed?) { true } + socket_spy.stub(:readpartial) { chunks.shift } + socket_spy.stub(:<<) { nil } + + TCPSocket.stub(:open) { socket_spy } + end + + it 'properly reads body' do + body = client.get("http://127.0.0.1:#{ExampleService::PORT}/").to_s + expect(body).to eq '' + end + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/content_type_spec.rb b/.gems/gems/http-0.6.2/spec/http/content_type_spec.rb new file mode 100644 index 0000000..b27379f --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/content_type_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe HTTP::ContentType do + describe '.parse' do + context 'with text/plain' do + subject { described_class.parse 'text/plain' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should be_nil } + end + + context 'with tEXT/plaIN' do + subject { described_class.parse 'tEXT/plaIN' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should be_nil } + end + + context 'with text/plain; charset=utf-8' do + subject { described_class.parse 'text/plain; charset=utf-8' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should eq 'utf-8' } + end + + context 'with text/plain; charset="utf-8"' do + subject { described_class.parse 'text/plain; charset="utf-8"' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should eq 'utf-8' } + end + + context 'with text/plain; charSET=utf-8' do + subject { described_class.parse 'text/plain; charSET=utf-8' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should eq 'utf-8' } + end + + context 'with text/plain; foo=bar; charset=utf-8' do + subject { described_class.parse 'text/plain; foo=bar; charset=utf-8' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should eq 'utf-8' } + end + + context 'with text/plain;charset=utf-8;foo=bar' do + subject { described_class.parse 'text/plain;charset=utf-8;foo=bar' } + its(:mime_type) { should eq 'text/plain' } + its(:charset) { should eq 'utf-8' } + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/headers/mixin_spec.rb b/.gems/gems/http-0.6.2/spec/http/headers/mixin_spec.rb new file mode 100644 index 0000000..bd72c6d --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/headers/mixin_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe HTTP::Headers::Mixin do + let :dummy_class do + Class.new do + include HTTP::Headers::Mixin + + def initialize(headers) + @headers = headers + end + end + end + + let(:headers) { HTTP::Headers.new } + let(:dummy) { dummy_class.new headers } + + describe '#headers' do + it 'returns @headers instance variable' do + expect(dummy.headers).to be headers + end + end + + describe '#[]' do + it 'proxies to headers#[]' do + expect(headers).to receive(:[]).with(:accept) + dummy[:accept] + end + end + + describe '#[]=' do + it 'proxies to headers#[]' do + expect(headers).to receive(:[]=).with(:accept, 'text/plain') + dummy[:accept] = 'text/plain' + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/headers_spec.rb b/.gems/gems/http-0.6.2/spec/http/headers_spec.rb new file mode 100644 index 0000000..c362376 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/headers_spec.rb @@ -0,0 +1,417 @@ +require 'spec_helper' + +describe HTTP::Headers do + subject(:headers) { described_class.new } + + it 'is Enumerable' do + expect(headers).to be_an Enumerable + end + + describe '#set' do + it 'sets header value' do + headers.set 'Accept', 'application/json' + expect(headers['Accept']).to eq 'application/json' + end + + it 'normalizes header name' do + headers.set :content_type, 'application/json' + expect(headers['Content-Type']).to eq 'application/json' + end + + it 'overwrites previous value' do + headers.set :set_cookie, 'hoo=ray' + headers.set :set_cookie, 'woo=hoo' + expect(headers['Set-Cookie']).to eq 'woo=hoo' + end + + it 'allows set multiple values' do + headers.set :set_cookie, 'hoo=ray' + headers.set :set_cookie, %w[hoo=ray woo=hoo] + expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo] + end + end + + describe '#[]=' do + it 'sets header value' do + headers['Accept'] = 'application/json' + expect(headers['Accept']).to eq 'application/json' + end + + it 'normalizes header name' do + headers[:content_type] = 'application/json' + expect(headers['Content-Type']).to eq 'application/json' + end + + it 'overwrites previous value' do + headers[:set_cookie] = 'hoo=ray' + headers[:set_cookie] = 'woo=hoo' + expect(headers['Set-Cookie']).to eq 'woo=hoo' + end + + it 'allows set multiple values' do + headers[:set_cookie] = 'hoo=ray' + headers[:set_cookie] = %w[hoo=ray woo=hoo] + expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo] + end + end + + describe '#delete' do + before { headers.set 'Content-Type', 'application/json' } + + it 'removes given header' do + headers.delete 'Content-Type' + expect(headers['Content-Type']).to be_nil + end + + it 'normalizes header name' do + headers.delete :content_type + expect(headers['Content-Type']).to be_nil + end + end + + describe '#add' do + it 'sets header value' do + headers.add 'Accept', 'application/json' + expect(headers['Accept']).to eq 'application/json' + end + + it 'normalizes header name' do + headers.add :content_type, 'application/json' + expect(headers['Content-Type']).to eq 'application/json' + end + + it 'appends new value if header exists' do + headers.add :set_cookie, 'hoo=ray' + headers.add :set_cookie, 'woo=hoo' + expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo] + end + + it 'allows append multiple values' do + headers.add :set_cookie, 'hoo=ray' + headers.add :set_cookie, %w[woo=hoo yup=pie] + expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo yup=pie] + end + end + + describe '#get' do + before { headers.set 'Content-Type', 'application/json' } + + it 'returns array of associated values' do + expect(headers.get 'Content-Type').to eq %w[application/json] + end + + it 'normalizes header name' do + expect(headers.get :content_type).to eq %w[application/json] + end + + context 'when header does not exists' do + it 'returns empty array' do + expect(headers.get :accept).to eq [] + end + end + end + + describe '#[]' do + context 'when header does not exists' do + it 'returns nil' do + expect(headers[:accept]).to be_nil + end + end + + context 'when header has a single value' do + before { headers.set 'Content-Type', 'application/json' } + + it 'normalizes header name' do + expect(headers[:content_type]).to_not be_nil + end + + it 'returns it returns a single value' do + expect(headers[:content_type]).to eq 'application/json' + end + end + + context 'when header has a multiple values' do + before do + headers.add :set_cookie, 'hoo=ray' + headers.add :set_cookie, 'woo=hoo' + end + + it 'normalizes header name' do + expect(headers[:set_cookie]).to_not be_nil + end + + it 'returns array of associated values' do + expect(headers[:set_cookie]).to eq %w[hoo=ray woo=hoo] + end + end + end + + describe '#to_h' do + before do + headers.add :content_type, 'application/json' + headers.add :set_cookie, 'hoo=ray' + headers.add :set_cookie, 'woo=hoo' + end + + it 'returns a Hash' do + expect(headers.to_h).to be_a Hash + end + + it 'returns Hash with normalized keys' do + expect(headers.to_h.keys).to match_array %w[Content-Type Set-Cookie] + end + + context 'for a header with single value' do + it 'provides a value as is' do + expect(headers.to_h['Content-Type']).to eq 'application/json' + end + end + + context 'for a header with multiple values' do + it 'provides an array of values' do + expect(headers.to_h['Set-Cookie']).to eq %w[hoo=ray woo=hoo] + end + end + end + + describe '#to_a' do + before do + headers.add :content_type, 'application/json' + headers.add :set_cookie, 'hoo=ray' + headers.add :set_cookie, 'woo=hoo' + end + + it 'returns an Array' do + expect(headers.to_a).to be_a Array + end + + it 'returns Array of key/value pairs with normalized keys' do + expect(headers.to_a).to eq [ + %w[Content-Type application/json], + %w[Set-Cookie hoo=ray], + %w[Set-Cookie woo=hoo] + ] + end + end + + describe '#inspect' do + before { headers.set :set_cookie, %w[hoo=ray woo=hoo] } + subject { headers.inspect } + + it { should eq '#["hoo=ray", "woo=hoo"]}>' } + end + + describe '#keys' do + before do + headers.add :content_type, 'application/json' + headers.add :set_cookie, 'hoo=ray' + headers.add :set_cookie, 'woo=hoo' + end + + it 'returns uniq keys only' do + expect(headers.keys).to have_exactly(2).items + end + + it 'normalizes keys' do + expect(headers.keys).to include('Content-Type', 'Set-Cookie') + end + end + + describe '#each' do + before do + headers.add :set_cookie, 'hoo=ray' + headers.add :content_type, 'application/json' + headers.add :set_cookie, 'woo=hoo' + end + + it 'yields each key/value pair separatedly' do + expect { |b| headers.each(&b) }.to yield_control.exactly(3).times + end + + it 'yields headers in the same order they were added' do + expect { |b| headers.each(&b) }.to yield_successive_args( + %w[Set-Cookie hoo=ray], + %w[Content-Type application/json], + %w[Set-Cookie woo=hoo] + ) + end + end + + describe '.empty?' do + subject { headers.empty? } + + context 'initially' do + it { should be_true } + end + + context 'when header exists' do + before { headers.add :accept, 'text/plain' } + it { should be_false } + end + + context 'when last header was removed' do + before do + headers.add :accept, 'text/plain' + headers.delete :accept + end + + it { should be_true } + end + end + + describe '#hash' do + let(:left) { described_class.new } + let(:right) { described_class.new } + + it 'equals if two headers equals' do + left.add :accept, 'text/plain' + right.add :accept, 'text/plain' + + expect(left.hash).to eq right.hash + end + end + + describe '#==' do + let(:left) { described_class.new } + let(:right) { described_class.new } + + it 'compares header keys and values' do + left.add :accept, 'text/plain' + right.add :accept, 'text/plain' + + expect(left).to eq right + end + + it 'allows comparison with Array of key/value pairs' do + left.add :accept, 'text/plain' + expect(left).to eq [%w[Accept text/plain]] + end + + it 'sensitive to headers order' do + left.add :accept, 'text/plain' + left.add :cookie, 'woo=hoo' + right.add :cookie, 'woo=hoo' + right.add :accept, 'text/plain' + + expect(left).to_not eq right + end + + it 'sensitive to header values order' do + left.add :cookie, 'hoo=ray' + left.add :cookie, 'woo=hoo' + right.add :cookie, 'woo=hoo' + right.add :cookie, 'hoo=ray' + + expect(left).to_not eq right + end + end + + describe '#dup' do + before { headers.set :content_type, 'application/json' } + + subject(:dupped) { headers.dup } + + it { should be_a described_class } + it { should_not be headers } + + it 'has headers copied' do + expect(dupped[:content_type]).to eq 'application/json' + end + + context 'modifying a copy' do + before { dupped.set :content_type, 'text/plain' } + + it 'modifies dupped copy' do + expect(dupped[:content_type]).to eq 'text/plain' + end + + it 'does not affects original headers' do + expect(headers[:content_type]).to eq 'application/json' + end + end + end + + describe '#merge!' do + before do + headers.set :host, 'example.com' + headers.set :accept, 'application/json' + headers.merge! :accept => 'plain/text', :cookie => %w[hoo=ray woo=hoo] + end + + it 'leaves headers not presented in other as is' do + expect(headers[:host]).to eq 'example.com' + end + + it 'overwrites existing values' do + expect(headers[:accept]).to eq 'plain/text' + end + + it 'appends other headers, not presented in base' do + expect(headers[:cookie]).to eq %w[hoo=ray woo=hoo] + end + end + + describe '#merge' do + before do + headers.set :host, 'example.com' + headers.set :accept, 'application/json' + end + + subject(:merged) do + headers.merge :accept => 'plain/text', :cookie => %w[hoo=ray woo=hoo] + end + + it { should be_a described_class } + it { should_not be headers } + + it 'does not affects original headers' do + expect(merged.to_h).to_not eq headers.to_h + end + + it 'leaves headers not presented in other as is' do + expect(merged[:host]).to eq 'example.com' + end + + it 'overwrites existing values' do + expect(merged[:accept]).to eq 'plain/text' + end + + it 'appends other headers, not presented in base' do + expect(merged[:cookie]).to eq %w[hoo=ray woo=hoo] + end + end + + describe '.coerce' do + let(:dummyClass) { Class.new { def respond_to?(*); end } } + + it 'accepts any object that respond to #to_hash' do + hashie = double :to_hash => {'accept' => 'json'} + expect(described_class.coerce(hashie)['accept']).to eq 'json' + end + + it 'accepts any object that respond to #to_h' do + hashie = double :to_h => {'accept' => 'json'} + expect(described_class.coerce(hashie)['accept']).to eq 'json' + end + + it 'accepts any object that respond to #to_a' do + hashie = double :to_a => [%w[accept json]] + expect(described_class.coerce(hashie)['accept']).to eq 'json' + end + + it 'fails if given object cannot be coerced' do + expect { described_class.coerce dummyClass.new }.to raise_error HTTP::Error + end + + context 'with duplicate header keys (mixed case)' do + let(:headers) { {'Set-Cookie' => 'hoo=ray', 'set-cookie' => 'woo=hoo'} } + + it 'adds all headers' do + expect(described_class.coerce(headers).to_a).to match_array([ + %w[Set-Cookie hoo=ray], + %w[Set-Cookie woo=hoo] + ]) + end + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/body_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/body_spec.rb new file mode 100644 index 0000000..f25c8bb --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/body_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe HTTP::Options, 'body' do + + let(:opts) { HTTP::Options.new } + + it 'defaults to nil' do + expect(opts.body).to be nil + end + + it 'may be specified with with_body' do + opts2 = opts.with_body('foo') + expect(opts.body).to be nil + expect(opts2.body).to eq('foo') + end + +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/form_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/form_spec.rb new file mode 100644 index 0000000..61d1de5 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/form_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe HTTP::Options, 'form' do + + let(:opts) { HTTP::Options.new } + + it 'defaults to nil' do + expect(opts.form).to be nil + end + + it 'may be specified with with_form_data' do + opts2 = opts.with_form(:foo => 42) + expect(opts.form).to be nil + expect(opts2.form).to eq(:foo => 42) + end + +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/headers_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/headers_spec.rb new file mode 100644 index 0000000..5996445 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/headers_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe HTTP::Options, 'headers' do + + let(:opts) { HTTP::Options.new } + + it 'defaults to be empty' do + expect(opts.headers).to be_empty + end + + it 'may be specified with with_headers' do + opts2 = opts.with_headers('accept' => 'json') + expect(opts.headers).to be_empty + expect(opts2.headers).to eq([%w[Accept json]]) + end + + it 'accepts any object that respond to :to_hash' do + x = Struct.new(:to_hash).new('accept' => 'json') + expect(opts.with_headers(x).headers['accept']).to eq('json') + end + +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/json_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/json_spec.rb new file mode 100644 index 0000000..54f4776 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/json_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe HTTP::Options, 'json' do + + let(:opts) { HTTP::Options.new } + + it 'defaults to nil' do + expect(opts.json).to be nil + end + + it 'may be specified with with_json data' do + opts2 = opts.with_json(:foo => 42) + expect(opts.json).to be nil + expect(opts2.json).to eq(:foo => 42) + end + +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/merge_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/merge_spec.rb new file mode 100644 index 0000000..a721f4f --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/merge_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe HTTP::Options, 'merge' do + let(:opts) { HTTP::Options.new } + + it 'supports a Hash' do + old_response = opts.response + expect(opts.merge(:response => :body).response).to eq(:body) + expect(opts.response).to eq(old_response) + end + + it 'supports another Options' do + merged = opts.merge(HTTP::Options.new(:response => :body)) + expect(merged.response).to eq(:body) + end + + it 'merges as excepted in complex cases' do + # FIXME: yuck :( + + foo = HTTP::Options.new( + :response => :body, + :params => {:baz => 'bar'}, + :form => {:foo => 'foo'}, + :body => 'body-foo', + :json => {:foo => 'foo'}, + :headers => {:accept => 'json', :foo => 'foo'}, + :proxy => {}) + + bar = HTTP::Options.new( + :response => :parsed_body, + :params => {:plop => 'plip'}, + :form => {:bar => 'bar'}, + :body => 'body-bar', + :json => {:bar => 'bar'}, + :headers => {:accept => 'xml', :bar => 'bar'}, + :proxy => {:proxy_address => '127.0.0.1', :proxy_port => 8080}) + + expect(foo.merge(bar).to_hash).to eq( + :response => :parsed_body, + :params => {:plop => 'plip'}, + :form => {:bar => 'bar'}, + :body => 'body-bar', + :json => {:bar => 'bar'}, + :headers => {'Accept' => 'xml', 'Foo' => 'foo', 'Bar' => 'bar'}, + :proxy => {:proxy_address => '127.0.0.1', :proxy_port => 8080}, + :follow => nil, + :socket_class => described_class.default_socket_class, + :ssl_socket_class => described_class.default_ssl_socket_class, + :ssl_context => nil) + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/new_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/new_spec.rb new file mode 100644 index 0000000..845b447 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/new_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe HTTP::Options, 'new' do + it 'supports a Options instance' do + opts = HTTP::Options.new + expect(HTTP::Options.new(opts)).to eq(opts) + end + + context 'with a Hash' do + it 'coerces :response correctly' do + opts = HTTP::Options.new(:response => :object) + expect(opts.response).to eq(:object) + end + + it 'coerces :headers correctly' do + opts = HTTP::Options.new(:headers => {:accept => 'json'}) + expect(opts.headers).to eq([%w[Accept json]]) + end + + it 'coerces :proxy correctly' do + opts = HTTP::Options.new(:proxy => {:proxy_address => '127.0.0.1', :proxy_port => 8080}) + expect(opts.proxy).to eq(:proxy_address => '127.0.0.1', :proxy_port => 8080) + end + + it 'coerces :form correctly' do + opts = HTTP::Options.new(:form => {:foo => 42}) + expect(opts.form).to eq(:foo => 42) + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/options/proxy_spec.rb b/.gems/gems/http-0.6.2/spec/http/options/proxy_spec.rb new file mode 100644 index 0000000..b1c9e37 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options/proxy_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe HTTP::Options, 'proxy' do + + let(:opts) { HTTP::Options.new } + + it 'defaults to {}' do + expect(opts.proxy).to eq({}) + end + + it 'may be specified with with_proxy' do + opts2 = opts.with_proxy(:proxy_address => '127.0.0.1', :proxy_port => 8080) + expect(opts.proxy).to eq({}) + expect(opts2.proxy).to eq(:proxy_address => '127.0.0.1', :proxy_port => 8080) + end + + it 'accepts proxy address, port, username, and password' do + opts2 = opts.with_proxy(:proxy_address => '127.0.0.1', :proxy_port => 8080, :proxy_username => 'username', :proxy_password => 'password') + expect(opts2.proxy).to eq(:proxy_address => '127.0.0.1', :proxy_port => 8080, :proxy_username => 'username', :proxy_password => 'password') + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/options_spec.rb b/.gems/gems/http-0.6.2/spec/http/options_spec.rb new file mode 100644 index 0000000..f2bf76b --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/options_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe HTTP::Options do + subject { described_class.new(:response => :body) } + + it 'behaves like a Hash for reading' do + expect(subject[:response]).to eq(:body) + expect(subject[:nosuchone]).to be nil + end + + it 'coerces to a Hash' do + expect(subject.to_hash).to be_a(Hash) + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/redirector_spec.rb b/.gems/gems/http-0.6.2/spec/http/redirector_spec.rb new file mode 100644 index 0000000..b40018b --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/redirector_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +describe HTTP::Redirector do + def simple_response(status, body = '', headers = {}) + HTTP::Response.new(status, '1.1', headers, body) + end + + def redirect_response(location, status) + simple_response status, '', 'Location' => location + end + + let(:max_hops) { 5 } + subject(:redirector) { described_class.new max_hops } + + context 'following 300 redirect' do + let(:orig_request) { HTTP::Request.new :post, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 300 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be orig_request.verb + simple_response 200 + end + end + end + + context 'following 301 redirect' do + let(:orig_request) { HTTP::Request.new :post, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 301 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be orig_request.verb + simple_response 200 + end + end + end + + context 'following 302 redirect' do + let(:orig_request) { HTTP::Request.new :post, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 302 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be orig_request.verb + simple_response 200 + end + end + end + + context 'following 303 redirect' do + context 'upon POST request' do + let(:orig_request) { HTTP::Request.new :post, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 303 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be :get + simple_response 200 + end + end + end + + context 'upon HEAD request' do + let(:orig_request) { HTTP::Request.new :head, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 303 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be :get + simple_response 200 + end + end + end + end + + context 'following 307 redirect' do + let(:orig_request) { HTTP::Request.new :post, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 307 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be orig_request.verb + simple_response 200 + end + end + end + + context 'following 308 redirect' do + let(:orig_request) { HTTP::Request.new :post, 'http://www.example.com/' } + let(:orig_response) { redirect_response 'http://example.com/', 308 } + + it 'follows without changing verb' do + redirector.perform(orig_request, orig_response) do |request| + expect(request.verb).to be orig_request.verb + simple_response 200 + end + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/request/writer_spec.rb b/.gems/gems/http-0.6.2/spec/http/request/writer_spec.rb new file mode 100644 index 0000000..026dbdd --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/request/writer_spec.rb @@ -0,0 +1,43 @@ +# coding: utf-8 + +require 'spec_helper' + +describe HTTP::Request::Writer do + describe '#initalize' do + def construct(body) + HTTP::Request::Writer.new(nil, body, [], '') + end + + it "doesn't throw on a nil body" do + expect { construct nil }.not_to raise_error + end + + it "doesn't throw on a String body" do + expect { construct 'string body' }.not_to raise_error + end + + it "doesn't throw on an Enumerable body" do + expect { construct %w[bees cows] }.not_to raise_error + end + + it "does throw on a body that isn't string, enumerable or nil" do + expect { construct true }.to raise_error + end + + it 'writes a chunked request from an Enumerable correctly' do + io = StringIO.new + writer = HTTP::Request::Writer.new(io, %w[bees cows], [], '') + writer.send_request_body + io.rewind + expect(io.string).to eq "4\r\nbees\r\n4\r\ncows\r\n0\r\n\r\n" + end + end + + describe '#add_body_type_headers' do + it 'properly calculates length of unicode string' do + writer = HTTP::Request::Writer.new(nil, 'Привет, мир!', {}, '') + writer.add_body_type_headers + expect(writer.join_headers).to match(/\r\nContent-Length: 21\r\n/) + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/request_spec.rb b/.gems/gems/http-0.6.2/spec/http/request_spec.rb new file mode 100644 index 0000000..4963f18 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/request_spec.rb @@ -0,0 +1,147 @@ +require 'spec_helper' + +describe HTTP::Request do + let(:headers) { {:accept => 'text/html'} } + let(:request_uri) { 'http://example.com/' } + + subject(:request) { HTTP::Request.new(:get, request_uri, headers) } + + it 'includes HTTP::Headers::Mixin' do + expect(described_class).to include HTTP::Headers::Mixin + end + + it 'requires URI to have scheme part' do + expect { HTTP::Request.new(:get, 'example.com/') }.to \ + raise_error(HTTP::Request::UnsupportedSchemeError) + end + + it 'provides a #scheme accessor' do + expect(request.scheme).to eq(:http) + end + + it 'sets given headers' do + expect(subject['Accept']).to eq('text/html') + end + + describe 'Host header' do + subject { request['Host'] } + + context 'was not given' do + it { is_expected.to eq 'example.com' } + + context 'and request URI has non-standard port' do + let(:request_uri) { 'http://example.com:3000/' } + it { is_expected.to eq 'example.com:3000' } + end + end + + context 'was explicitly given' do + before { headers[:host] = 'github.com' } + it { is_expected.to eq 'github.com' } + end + end + + describe 'User-Agent header' do + subject { request['User-Agent'] } + + context 'was not given' do + it { is_expected.to eq HTTP::Request::USER_AGENT } + end + + context 'was explicitly given' do + before { headers[:user_agent] = 'MrCrawly/123' } + it { is_expected.to eq 'MrCrawly/123' } + end + end + + it 'provides a #verb accessor' do + expect(subject.verb).to eq(:get) + end + + it 'provides a #method accessor that outputs a deprecation warning and returns the verb' do + warning = capture_warning do + expect(subject.method).to eq(subject.verb) + end + expect(warning).to match(/\[DEPRECATION\] HTTP::Request#method is deprecated\. Use #verb instead\. For Object#method, use #__method__\.$/) + end + + it 'provides a #__method__ method that delegates to Object#method' do + expect(subject.__method__(:verb)).to be_a(Method) + end + + describe '#redirect' do + let(:headers) { {:accept => 'text/html'} } + let(:proxy) { {:proxy_username => 'douglas', :proxy_password => 'adams'} } + let(:body) { 'The Ultimate Question' } + let(:request) { HTTP::Request.new(:post, 'http://example.com/', headers, proxy, body) } + + subject(:redirected) { request.redirect 'http://blog.example.com/' } + + its(:uri) { should eq URI.parse 'http://blog.example.com/' } + + its(:verb) { should eq request.verb } + its(:body) { should eq request.body } + its(:proxy) { should eq request.proxy } + + it 'presets new Host header' do + expect(redirected['Host']).to eq 'blog.example.com' + end + + context 'with schema-less absolute URL given' do + subject(:redirected) { request.redirect '//another.example.com/blog' } + + its(:uri) { should eq URI.parse 'http://another.example.com/blog' } + + its(:verb) { should eq request.verb } + its(:body) { should eq request.body } + its(:proxy) { should eq request.proxy } + + it 'presets new Host header' do + expect(redirected['Host']).to eq 'another.example.com' + end + end + + context 'with relative URL given' do + subject(:redirected) { request.redirect '/blog' } + + its(:uri) { should eq URI.parse 'http://example.com/blog' } + + its(:verb) { should eq request.verb } + its(:body) { should eq request.body } + its(:proxy) { should eq request.proxy } + + it 'keeps Host header' do + expect(redirected['Host']).to eq 'example.com' + end + + context 'with original URI having non-standard port' do + let(:request) { HTTP::Request.new(:post, 'http://example.com:8080/', headers, proxy, body) } + its(:uri) { should eq URI.parse 'http://example.com:8080/blog' } + end + end + + context 'with relative URL that misses leading slash given' do + subject(:redirected) { request.redirect 'blog' } + + its(:uri) { should eq URI.parse 'http://example.com/blog' } + + its(:verb) { should eq request.verb } + its(:body) { should eq request.body } + its(:proxy) { should eq request.proxy } + + it 'keeps Host header' do + expect(redirected['Host']).to eq 'example.com' + end + + context 'with original URI having non-standard port' do + let(:request) { HTTP::Request.new(:post, 'http://example.com:8080/', headers, proxy, body) } + its(:uri) { should eq URI.parse 'http://example.com:8080/blog' } + end + end + + context 'with new verb given' do + subject { request.redirect 'http://blog.example.com/', :get } + its(:verb) { should be :get } + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/response/body_spec.rb b/.gems/gems/http-0.6.2/spec/http/response/body_spec.rb new file mode 100644 index 0000000..fb5989c --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/response/body_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe HTTP::Response::Body do + let(:client) { double } + let(:chunks) { ['Hello, ', 'World!'] } + + before { allow(client).to receive(:readpartial) { chunks.shift } } + + subject(:body) { described_class.new client } + + it 'streams bodies from responses' do + expect(subject.to_s).to eq 'Hello, World!' + end + + context 'when body empty' do + let(:chunks) { [''] } + + it 'returns responds to empty? with true' do + expect(subject).to be_empty + end + end + + describe '#readpartial' do + context 'with size given' do + it 'passes value to underlying client' do + expect(client).to receive(:readpartial).with(42) + body.readpartial 42 + end + end + + context 'without size given' do + it 'does not blows up' do + expect { body.readpartial }.to_not raise_error + end + + it 'calls underlying client readpartial without specific size' do + expect(client).to receive(:readpartial).with no_args + body.readpartial + end + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http/response_spec.rb b/.gems/gems/http-0.6.2/spec/http/response_spec.rb new file mode 100644 index 0000000..c554cc1 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http/response_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +describe HTTP::Response do + it 'includes HTTP::Headers::Mixin' do + expect(described_class).to include HTTP::Headers::Mixin + end + + describe 'to_a' do + let(:body) { 'Hello world' } + let(:content_type) { 'text/plain' } + subject { HTTP::Response.new(200, '1.1', {'Content-Type' => content_type}, body) } + + it 'returns a Rack-like array' do + expect(subject.to_a).to eq([200, {'Content-Type' => content_type}, body]) + end + end + + describe 'mime_type' do + subject { HTTP::Response.new(200, '1.1', headers, '').mime_type } + + context 'without Content-Type header' do + let(:headers) { {} } + it { should be_nil } + end + + context 'with Content-Type: text/html' do + let(:headers) { {'Content-Type' => 'text/html'} } + it { should eq 'text/html' } + end + + context 'with Content-Type: text/html; charset=utf-8' do + let(:headers) { {'Content-Type' => 'text/html; charset=utf-8'} } + it { should eq 'text/html' } + end + end + + describe 'charset' do + subject { HTTP::Response.new(200, '1.1', headers, '').charset } + + context 'without Content-Type header' do + let(:headers) { {} } + it { should be_nil } + end + + context 'with Content-Type: text/html' do + let(:headers) { {'Content-Type' => 'text/html'} } + it { should be_nil } + end + + context 'with Content-Type: text/html; charset=utf-8' do + let(:headers) { {'Content-Type' => 'text/html; charset=utf-8'} } + it { should eq 'utf-8' } + end + end + + describe '#parse' do + let(:headers) { {'Content-Type' => content_type} } + let(:body) { '{"foo":"bar"}' } + let(:response) { HTTP::Response.new 200, '1.1', headers, body } + + context 'with known content type' do + let(:content_type) { 'application/json' } + it 'returns parsed body' do + expect(response.parse).to eq 'foo' => 'bar' + end + end + + context 'with unknown content type' do + let(:content_type) { 'application/deadbeef' } + it 'raises HTTP::Error' do + expect { response.parse }.to raise_error HTTP::Error + end + end + + context 'with explicitly given mime type' do + let(:content_type) { 'application/deadbeef' } + it 'ignores mime_type of response' do + expect(response.parse 'application/json').to eq 'foo' => 'bar' + end + + it 'supports MIME type aliases' do + expect(response.parse :json).to eq 'foo' => 'bar' + end + end + end + + describe '#flush' do + let(:body) { double :to_s => '' } + let(:response) { HTTP::Response.new 200, '1.1', {}, body } + + it 'returns response self-reference' do + expect(response.flush).to be response + end + + it 'flushes body' do + expect(body).to receive :to_s + response.flush + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/http_spec.rb b/.gems/gems/http-0.6.2/spec/http_spec.rb new file mode 100644 index 0000000..43ace3d --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/http_spec.rb @@ -0,0 +1,136 @@ +require 'spec_helper' +require 'json' + +describe HTTP do + let(:test_endpoint) { "http://127.0.0.1:#{ExampleService::PORT}/" } + + context 'getting resources' do + it 'should be easy' do + response = HTTP.get test_endpoint + expect(response.to_s).to match(//) + end + + context 'with URI instance' do + it 'should be easy' do + response = HTTP.get URI(test_endpoint) + expect(response.to_s).to match(//) + end + end + + context 'with query string parameters' do + it 'is easy' do + response = HTTP.get "#{test_endpoint}params", :params => {:foo => 'bar'} + expect(response.to_s).to match(/Params!/) + end + end + + context 'with query string parameters in the URI and opts hash' do + it 'includes both' do + response = HTTP.get "#{test_endpoint}multiple-params?foo=bar", :params => {:baz => 'quux'} + expect(response.to_s).to match(/More Params!/) + end + end + + context 'with headers' do + it 'should be easy' do + response = HTTP.accept('application/json').get test_endpoint + expect(response.to_s.include?('json')).to be true + end + end + end + + context 'with http proxy address and port' do + it 'should proxy the request' do + response = HTTP.via('127.0.0.1', 8080).get test_endpoint + expect(response.headers['X-Proxied']).to eq 'true' + end + end + + context 'with http proxy address, port username and password' do + it 'should proxy the request' do + response = HTTP.via('127.0.0.1', 8081, 'username', 'password').get test_endpoint + expect(response.headers['X-Proxied']).to eq 'true' + end + + it 'responds with the endpoint\'s body' do + response = HTTP.via('127.0.0.1', 8081, 'username', 'password').get test_endpoint + expect(response.to_s).to match(//) + end + end + + context 'with http proxy address, port, with wrong username and password' do + it 'responds with 407' do + response = HTTP.via('127.0.0.1', 8081, 'user', 'pass').get test_endpoint + expect(response.status).to eq(407) + end + end + + context 'without proxy port' do + it 'should raise an argument error' do + expect { HTTP.via('127.0.0.1') }.to raise_error HTTP::RequestError + end + end + + context 'posting to resources' do + it 'should be easy to post forms' do + response = HTTP.post "#{test_endpoint}form", :form => {:example => 'testing-form'} + expect(response.to_s).to eq('passed :)') + end + end + + context 'posting with an explicit body' do + it 'should be easy to post' do + response = HTTP.post "#{test_endpoint}body", :body => 'testing-body' + expect(response.to_s).to eq('passed :)') + end + end + + context 'with redirects' do + it 'should be easy for 301' do + response = HTTP.with_follow(true).get("#{test_endpoint}redirect-301") + expect(response.to_s).to match(//) + end + + it 'should be easy for 302' do + response = HTTP.with_follow(true).get("#{test_endpoint}redirect-302") + expect(response.to_s).to match(//) + end + + end + + context 'head requests' do + it 'should be easy' do + response = HTTP.head test_endpoint + expect(response.status).to eq(200) + expect(response['content-type']).to match(/html/) + end + end + + describe '.auth' do + context 'with no arguments' do + specify { expect { HTTP.auth }.to raise_error } + end + + context 'with one argument' do + it 'returns branch with Authorization header as is' do + expect(HTTP).to receive(:with) \ + .with :authorization => 'foobar' + + HTTP.auth :foobar + end + end + + context 'with two arguments' do + it 'builds value with AuthorizationHeader builder' do + expect(HTTP::AuthorizationHeader).to receive(:build) \ + .with(:bearer, :token => 'token') + + HTTP.auth :bearer, :token => 'token' + end + end + + context 'with more than two arguments' do + specify { expect { HTTP.auth 1, 2, 3 }.to raise_error } + end + end +end diff --git a/.gems/gems/http-0.6.2/spec/spec_helper.rb b/.gems/gems/http-0.6.2/spec/spec_helper.rb new file mode 100644 index 0000000..d4fc208 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/spec_helper.rb @@ -0,0 +1,33 @@ +if RUBY_VERSION >= '1.9' + require 'simplecov' + require 'coveralls' + + SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter] + + SimpleCov.start do + add_filter '/spec/' + minimum_coverage(80) + end +end + +require 'http' +require 'support/example_server' +require 'support/proxy_server' + +RSpec.configure do |config| + config.expect_with :rspec do |c| + c.syntax = :expect + end +end + +def capture_warning + begin + old_stderr = $stderr + $stderr = StringIO.new + yield + result = $stderr.string + ensure + $stderr = old_stderr + end + result +end diff --git a/.gems/gems/http-0.6.2/spec/support/example_server.rb b/.gems/gems/http-0.6.2/spec/support/example_server.rb new file mode 100644 index 0000000..77b4d96 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/support/example_server.rb @@ -0,0 +1,102 @@ +require 'webrick' + +class ExampleService < WEBrick::HTTPServlet::AbstractServlet + PORT = 65432 # rubocop:disable NumericLiterals + + def do_GET(request, response) # rubocop:disable MethodName + case request.path + when '/' + handle_root(request, response) + when '/params' + handle_params(request, response) + when '/multiple-params' + handle_multiple_params(request, response) + when '/proxy' + response.status = 200 + response.body = 'Proxy!' + when '/not-found' + response.body = 'not found' + response.status = 404 + when '/redirect-301' + response.status = 301 + response['Location'] = "http://127.0.0.1:#{PORT}/" + when '/redirect-302' + response.status = 302 + response['Location'] = "http://127.0.0.1:#{PORT}/" + else + response.status = 404 + end + end + + def handle_root(request, response) + response.status = 200 + case request['Accept'] + when 'application/json' + response['Content-Type'] = 'application/json' + response.body = '{"json": true}' + else + response['Content-Type'] = 'text/html' + response.body = '' + end + end + + def handle_params(request, response) + return unless request.query_string == 'foo=bar' + + response.status = 200 + response.body = 'Params!' + end + + def handle_multiple_params(request, response) + params = CGI.parse(request.query_string) + + return unless params == {'foo' => ['bar'], 'baz' => ['quux']} + + response.status = 200 + response.body = 'More Params!' + end + + def do_POST(request, response) # rubocop:disable MethodName + case request.path + when '/form' + if request.query['example'] == 'testing-form' + response.status = 200 + response.body = 'passed :)' + else + response.status = 400 + response.body = 'invalid! >:E' + end + when '/body' + if request.body == 'testing-body' + response.status = 200 + response.body = 'passed :)' + else + response.status = 400 + response.body = 'invalid! >:E' + end + else + response.status = 404 + end + end + + def do_HEAD(request, response) # rubocop:disable MethodName + case request.path + when '/' + response.status = 200 + response['Content-Type'] = 'text/html' + else + response.status = 404 + end + end +end + +ExampleServer = WEBrick::HTTPServer.new(:Port => ExampleService::PORT, :AccessLog => []) +ExampleServer.mount '/', ExampleService + +t = Thread.new { ExampleServer.start } +trap('INT') do + ExampleServer.shutdown + exit +end + +Thread.pass while t.status && t.status != 'sleep' diff --git a/.gems/gems/http-0.6.2/spec/support/proxy_server.rb b/.gems/gems/http-0.6.2/spec/support/proxy_server.rb new file mode 100644 index 0000000..d990926 --- /dev/null +++ b/.gems/gems/http-0.6.2/spec/support/proxy_server.rb @@ -0,0 +1,31 @@ +require 'webrick/httpproxy' + +handler = proc { |_, res| res['X-PROXIED'] = true } + +ProxyServer = WEBrick::HTTPProxyServer.new( + :Port => 8080, + :AccessLog => [], + :RequestCallback => handler +) + +AuthenticatedProxyServer = WEBrick::HTTPProxyServer.new( + :Port => 8081, + :ProxyAuthProc => proc do | req, res | + WEBrick::HTTPAuth.proxy_basic_auth(req, res, 'proxy') do | user, pass | + user == 'username' && pass == 'password' + end + end, + :RequestCallback => handler +) + +Thread.new { ProxyServer.start } +trap('INT') do + ProxyServer.shutdown + exit +end + +Thread.new { AuthenticatedProxyServer.start } +trap('INT') do + AuthenticatedProxyServer.shutdown + exit +end diff --git a/.gems/gems/http_parser.rb-0.6.0/.gitignore b/.gems/gems/http_parser.rb-0.6.0/.gitignore new file mode 100644 index 0000000..d20f94b --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/.gitignore @@ -0,0 +1,11 @@ +tmp +*.bundle +*.gem +*.o +*.so +*.bundle +*.jar +*.swp +Makefile +tags +*.rbc diff --git a/.gems/gems/http_parser.rb-0.6.0/.gitmodules b/.gems/gems/http_parser.rb-0.6.0/.gitmodules new file mode 100644 index 0000000..6c289a3 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/.gitmodules @@ -0,0 +1,6 @@ +[submodule "http-parser"] + path = ext/ruby_http_parser/vendor/http-parser + url = git://github.com/joyent/http-parser.git +[submodule "http-parser-java"] + path = ext/ruby_http_parser/vendor/http-parser-java + url = git://github.com/tmm1/http-parser.java diff --git a/.gems/gems/http_parser.rb-0.6.0/Gemfile b/.gems/gems/http_parser.rb-0.6.0/Gemfile new file mode 100644 index 0000000..851fabc --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gemspec diff --git a/.gems/gems/http_parser.rb-0.6.0/Gemfile.lock b/.gems/gems/http_parser.rb-0.6.0/Gemfile.lock new file mode 100644 index 0000000..c880187 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/Gemfile.lock @@ -0,0 +1,39 @@ +PATH + remote: . + specs: + http_parser.rb (0.6.0.beta.2) + +GEM + remote: https://rubygems.org/ + specs: + benchmark_suite (0.8.0) + diff-lcs (1.1.2) + ffi (1.0.11) + ffi (1.0.11-java) + json (1.8.0) + json (1.8.0-java) + rake (0.9.2) + rake-compiler (0.7.9) + rake + rspec (2.4.0) + rspec-core (~> 2.4.0) + rspec-expectations (~> 2.4.0) + rspec-mocks (~> 2.4.0) + rspec-core (2.4.0) + rspec-expectations (2.4.0) + diff-lcs (~> 1.1.2) + rspec-mocks (2.4.0) + yajl-ruby (1.1.0) + +PLATFORMS + java + ruby + +DEPENDENCIES + benchmark_suite + ffi + http_parser.rb! + json (>= 1.4.6) + rake-compiler (>= 0.7.9) + rspec (>= 2.0.1) + yajl-ruby (>= 0.8.1) diff --git a/.gems/gems/http_parser.rb-0.6.0/LICENSE-MIT b/.gems/gems/http_parser.rb-0.6.0/LICENSE-MIT new file mode 100644 index 0000000..35f0bf0 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright 2009,2010 Marc-André Cournoyer +Copyright 2010,2011 Aman Gupta + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/.gems/gems/http_parser.rb-0.6.0/README.md b/.gems/gems/http_parser.rb-0.6.0/README.md new file mode 100644 index 0000000..35dad45 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/README.md @@ -0,0 +1,90 @@ +# http_parser.rb + +A simple callback-based HTTP request/response parser for writing http +servers, clients and proxies. + +This gem is built on top of [joyent/http-parser](http://github.com/joyent/http-parser) and its java port [http-parser/http-parser.java](http://github.com/http-parser/http-parser.java). + +## Supported Platforms + +This gem aims to work on all major Ruby platforms, including: + +- MRI 1.8 and 1.9 +- Rubinius +- JRuby +- win32 + +## Usage + +```ruby +require "http/parser" + +parser = Http::Parser.new + +parser.on_headers_complete = proc do + p parser.http_version + + p parser.http_method # for requests + p parser.request_url + + p parser.status_code # for responses + + p parser.headers +end + +parser.on_body = proc do |chunk| + # One chunk of the body + p chunk +end + +parser.on_message_complete = proc do |env| + # Headers and body is all parsed + puts "Done!" +end +``` + +# Feed raw data from the socket to the parser +`parser << raw_data` + +## Advanced Usage + +### Accept callbacks on an object + +```ruby +module MyHttpConnection + def connection_completed + @parser = Http::Parser.new(self) + end + + def receive_data(data) + @parser << data + end + + def on_message_begin + @headers = nil + @body = '' + end + + def on_headers_complete(headers) + @headers = headers + end + + def on_body(chunk) + @body << chunk + end + + def on_message_complete + p [@headers, @body] + end +end +``` + +### Stop parsing after headers + +```ruby +parser = Http::Parser.new +parser.on_headers_complete = proc{ :stop } + +offset = parser << request_data +body = request_data[offset..-1] +``` diff --git a/.gems/gems/http_parser.rb-0.6.0/Rakefile b/.gems/gems/http_parser.rb-0.6.0/Rakefile new file mode 100644 index 0000000..150f652 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/Rakefile @@ -0,0 +1,6 @@ +# load tasks +Dir['tasks/*.rake'].sort.each { |f| load f } + +# default task +task :compile => :submodules +task :default => [:compile, :spec] diff --git a/.gems/gems/http_parser.rb-0.6.0/bench/standalone.rb b/.gems/gems/http_parser.rb-0.6.0/bench/standalone.rb new file mode 100755 index 0000000..6b4dcb6 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/bench/standalone.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +$:.unshift File.dirname(__FILE__) + "/../lib" +require "rubygems" +require "http/parser" +require "benchmark/ips" + +request = <<-REQUEST +GET / HTTP/1.1 +Host: www.example.com +Connection: keep-alive +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.78 S +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Encoding: gzip,deflate,sdch +Accept-Language: en-US,en;q=0.8 +Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 + +REQUEST +request.gsub!(/\n/m, "\r\n") + +Benchmark.ips do |ips| + ips.report("instance") { Http::Parser.new } + ips.report("parsing") { Http::Parser.new << request } +end diff --git a/.gems/gems/http_parser.rb-0.6.0/bench/thin.rb b/.gems/gems/http_parser.rb-0.6.0/bench/thin.rb new file mode 100644 index 0000000..fe0dd6d --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/bench/thin.rb @@ -0,0 +1,58 @@ +$:.unshift File.dirname(__FILE__) + "/../lib" +require "rubygems" +require "thin_parser" +require "http_parser" +require "benchmark" +require "stringio" + +data = "POST /postit HTTP/1.1\r\n" + + "Host: localhost:3000\r\n" + + "User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9\r\n" + + "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\n" + + "Accept-Language: en-us,en;q=0.5\r\n" + + "Accept-Encoding: gzip,deflate\r\n" + + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" + + "Keep-Alive: 300\r\n" + + "Connection: keep-alive\r\n" + + "Content-Type: text/html\r\n" + + "Content-Length: 37\r\n" + + "\r\n" + + "name=marc&email=macournoyer@gmail.com" + +def thin(data) + env = {"rack.input" => StringIO.new} + Thin::HttpParser.new.execute(env, data, 0) + env +end + +def http_parser(data) + body = StringIO.new + env = nil + + parser = HTTP::RequestParser.new + parser.on_headers_complete = proc { |e| env = e } + parser.on_body = proc { |c| body << c } + parser << data + + env["rack-input"] = body + env +end + +# p thin(data) +# p http_parser(data) + +TESTS = 30_000 +Benchmark.bmbm do |results| + results.report("thin:") { TESTS.times { thin data } } + results.report("http-parser:") { TESTS.times { http_parser data } } +end + +# On my MBP core duo 2.2Ghz +# Rehearsal ------------------------------------------------ +# thin: 1.470000 0.000000 1.470000 ( 1.474737) +# http-parser: 1.270000 0.020000 1.290000 ( 1.292758) +# --------------------------------------- total: 2.760000sec +# +# user system total real +# thin: 1.150000 0.030000 1.180000 ( 1.173767) +# http-parser: 1.250000 0.010000 1.260000 ( 1.263796) diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.RUBYARCHDIR.time b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.RUBYARCHDIR.time new file mode 100644 index 0000000..e69de29 diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.gitignore b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.gitignore new file mode 100644 index 0000000..cb899d1 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/.gitignore @@ -0,0 +1 @@ +ryah_http_parser.* diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/RubyHttpParserService.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/RubyHttpParserService.java new file mode 100644 index 0000000..2ea3e8e --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/RubyHttpParserService.java @@ -0,0 +1,18 @@ +import java.io.IOException; + +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.runtime.load.BasicLibraryService; + +import org.ruby_http_parser.*; + +public class RubyHttpParserService implements BasicLibraryService { + public boolean basicLoad(final Ruby runtime) throws IOException { + RubyModule mHTTP = runtime.defineModule("HTTP"); + RubyClass cParser = mHTTP.defineClassUnder("Parser", runtime.getObject(), RubyHttpParser.ALLOCATOR); + cParser.defineAnnotatedMethods(RubyHttpParser.class); + cParser.defineClassUnder("Error", runtime.getClass("IOError"),runtime.getClass("IOError").getAllocator()); + return true; + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ext_help.h b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ext_help.h new file mode 100644 index 0000000..a919dff --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ext_help.h @@ -0,0 +1,18 @@ +#ifndef ext_help_h +#define ext_help_h + +#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be."); +#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name); +#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T); + +/* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_PTR */ +#ifndef RSTRING_PTR +#define RSTRING_PTR(s) (RSTRING(s)->ptr) +#endif + +/* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_LEN */ +#ifndef RSTRING_LEN +#define RSTRING_LEN(s) (RSTRING(s)->len) +#endif + +#endif diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/extconf.rb b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/extconf.rb new file mode 100644 index 0000000..d2f6e51 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/extconf.rb @@ -0,0 +1,24 @@ +require 'mkmf' + +# check out code if it hasn't been already +if Dir[File.expand_path('../vendor/http-parser/*', __FILE__)].empty? + Dir.chdir(File.expand_path('../../../', __FILE__)) do + xsystem 'git submodule init' + xsystem 'git submodule update' + end +end + +# mongrel and http-parser both define http_parser_(init|execute), so we +# rename functions in http-parser before using them. +vendor_dir = File.expand_path('../vendor/http-parser/', __FILE__) +src_dir = File.expand_path('../', __FILE__) +%w[ http_parser.c http_parser.h ].each do |file| + File.open(File.join(src_dir, "ryah_#{file}"), 'w'){ |f| + f.write File.read(File.join(vendor_dir, file)).gsub('http_parser', 'ryah_http_parser') + } +end + +$CFLAGS << " -I#{src_dir}" + +dir_config("ruby_http_parser") +create_makefile("ruby_http_parser") diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java new file mode 100644 index 0000000..ac586a9 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java @@ -0,0 +1,495 @@ +package org.ruby_http_parser; + +import http_parser.HTTPException; +import http_parser.HTTPMethod; +import http_parser.HTTPParser; +import http_parser.lolevel.HTTPCallback; +import http_parser.lolevel.HTTPDataCallback; +import http_parser.lolevel.ParserSettings; + +import java.nio.ByteBuffer; + +import org.jcodings.Encoding; +import org.jcodings.specific.UTF8Encoding; +import org.jruby.Ruby; +import org.jruby.RubyArray; +import org.jruby.RubyClass; +import org.jruby.RubyHash; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.RubySymbol; +import org.jruby.anno.JRubyMethod; +import org.jruby.exceptions.RaiseException; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; + +public class RubyHttpParser extends RubyObject { + + @JRubyMethod(name = "strict?", module = true) + public static IRubyObject strict(IRubyObject recv) { + return recv.getRuntime().newBoolean(true); + } + + public static ObjectAllocator ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klass) { + return new RubyHttpParser(runtime, klass); + } + }; + + byte[] fetchBytes(ByteBuffer b, int pos, int len) { + byte[] by = new byte[len]; + int saved = b.position(); + b.position(pos); + b.get(by); + b.position(saved); + return by; + } + + public class StopException extends RuntimeException { + } + + private Ruby runtime; + private HTTPParser parser; + private ParserSettings settings; + + private RubyClass eParserError; + + private RubyHash headers; + + private IRubyObject on_message_begin; + private IRubyObject on_headers_complete; + private IRubyObject on_body; + private IRubyObject on_message_complete; + + private IRubyObject requestUrl; + private IRubyObject requestPath; + private IRubyObject queryString; + private IRubyObject fragment; + + private IRubyObject header_value_type; + private IRubyObject upgradeData; + + private IRubyObject callback_object; + + private boolean completed; + + private byte[] _current_header; + private byte[] _last_header; + + private static final Encoding UTF8 = UTF8Encoding.INSTANCE; + + public RubyHttpParser(final Ruby runtime, RubyClass clazz) { + super(runtime, clazz); + + this.runtime = runtime; + this.eParserError = (RubyClass) runtime.getModule("HTTP").getClass("Parser").getConstant("Error"); + + this.on_message_begin = null; + this.on_headers_complete = null; + this.on_body = null; + this.on_message_complete = null; + + this.callback_object = null; + + this.completed = false; + + this.header_value_type = runtime.getModule("HTTP").getClass("Parser") + .getInstanceVariable("@default_header_value_type"); + + initSettings(); + init(); + } + + private void initSettings() { + this.settings = new ParserSettings(); + + this.settings.on_url = new HTTPDataCallback() { + public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) { + byte[] data = fetchBytes(buf, pos, len); + if (runtime.is1_9() || runtime.is2_0()) { + ((RubyString) requestUrl).cat(data, 0, data.length, UTF8); + } else { + ((RubyString) requestUrl).cat(data); + } + return 0; + } + }; + + this.settings.on_header_field = new HTTPDataCallback() { + public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) { + byte[] data = fetchBytes(buf, pos, len); + + if (_current_header == null) + _current_header = data; + else { + byte[] tmp = new byte[_current_header.length + data.length]; + System.arraycopy(_current_header, 0, tmp, 0, _current_header.length); + System.arraycopy(data, 0, tmp, _current_header.length, data.length); + _current_header = tmp; + } + + return 0; + } + }; + final RubySymbol arraysSym = runtime.newSymbol("arrays"); + final RubySymbol mixedSym = runtime.newSymbol("mixed"); + final RubySymbol stopSym = runtime.newSymbol("stop"); + final RubySymbol resetSym = runtime.newSymbol("reset"); + this.settings.on_header_value = new HTTPDataCallback() { + public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) { + byte[] data = fetchBytes(buf, pos, len); + ThreadContext context = headers.getRuntime().getCurrentContext(); + IRubyObject key, val; + int new_field = 0; + + if (_current_header != null) { + new_field = 1; + _last_header = _current_header; + _current_header = null; + } + + key = RubyString.newString(runtime, new ByteList(_last_header, UTF8, false)); + val = headers.op_aref(context, key); + + if (new_field == 1) { + if (val.isNil()) { + if (header_value_type == arraysSym) { + headers.op_aset(context, key, + RubyArray.newArrayLight(runtime, RubyString.newStringLight(runtime, 10, UTF8))); + } else { + headers.op_aset(context, key, RubyString.newStringLight(runtime, 10, UTF8)); + } + } else { + if (header_value_type == mixedSym) { + if (val instanceof RubyString) { + headers.op_aset(context, key, + RubyArray.newArrayLight(runtime, val, RubyString.newStringLight(runtime, 10, UTF8))); + } else { + ((RubyArray) val).add(RubyString.newStringLight(runtime, 10, UTF8)); + } + } else if (header_value_type == arraysSym) { + ((RubyArray) val).add(RubyString.newStringLight(runtime, 10, UTF8)); + } else { + if (runtime.is1_9() || runtime.is2_0()) { + ((RubyString) val).cat(',', UTF8).cat(' ', UTF8); + } else { + ((RubyString) val).cat(',').cat(' '); + } + } + } + val = headers.op_aref(context, key); + } + + if (val instanceof RubyArray) { + val = ((RubyArray) val).entry(-1); + } + + if (runtime.is1_9() || runtime.is2_0()) { + ((RubyString) val).cat(data, 0, data.length, UTF8); + } else { + ((RubyString) val).cat(data); + } + + return 0; + } + }; + + this.settings.on_message_begin = new HTTPCallback() { + public int cb(http_parser.lolevel.HTTPParser p) { + headers = new RubyHash(runtime); + + if (runtime.is1_9() || runtime.is2_0()) { + requestUrl = RubyString.newEmptyString(runtime, UTF8); + requestPath = RubyString.newEmptyString(runtime, UTF8); + queryString = RubyString.newEmptyString(runtime, UTF8); + fragment = RubyString.newEmptyString(runtime, UTF8); + upgradeData = RubyString.newEmptyString(runtime, UTF8); + } else { + requestUrl = RubyString.newEmptyString(runtime); + requestPath = RubyString.newEmptyString(runtime); + queryString = RubyString.newEmptyString(runtime); + fragment = RubyString.newEmptyString(runtime); + upgradeData = RubyString.newEmptyString(runtime); + } + + IRubyObject ret = runtime.getNil(); + + if (callback_object != null) { + if (((RubyObject) callback_object).respondsTo("on_message_begin")) { + ThreadContext context = callback_object.getRuntime().getCurrentContext(); + ret = callback_object.callMethod(context, "on_message_begin"); + } + } else if (on_message_begin != null) { + ThreadContext context = on_message_begin.getRuntime().getCurrentContext(); + ret = on_message_begin.callMethod(context, "call"); + } + + if (ret == stopSym) { + throw new StopException(); + } else { + return 0; + } + } + }; + this.settings.on_message_complete = new HTTPCallback() { + public int cb(http_parser.lolevel.HTTPParser p) { + IRubyObject ret = runtime.getNil(); + + completed = true; + + if (callback_object != null) { + if (((RubyObject) callback_object).respondsTo("on_message_complete")) { + ThreadContext context = callback_object.getRuntime().getCurrentContext(); + ret = callback_object.callMethod(context, "on_message_complete"); + } + } else if (on_message_complete != null) { + ThreadContext context = on_message_complete.getRuntime().getCurrentContext(); + ret = on_message_complete.callMethod(context, "call"); + } + + if (ret == stopSym) { + throw new StopException(); + } else { + return 0; + } + } + }; + this.settings.on_headers_complete = new HTTPCallback() { + public int cb(http_parser.lolevel.HTTPParser p) { + IRubyObject ret = runtime.getNil(); + + if (callback_object != null) { + if (((RubyObject) callback_object).respondsTo("on_headers_complete")) { + ThreadContext context = callback_object.getRuntime().getCurrentContext(); + ret = callback_object.callMethod(context, "on_headers_complete", headers); + } + } else if (on_headers_complete != null) { + ThreadContext context = on_headers_complete.getRuntime().getCurrentContext(); + ret = on_headers_complete.callMethod(context, "call", headers); + } + + if (ret == stopSym) { + throw new StopException(); + } else if (ret == resetSym) { + return 1; + } else { + return 0; + } + } + }; + this.settings.on_body = new HTTPDataCallback() { + public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) { + IRubyObject ret = runtime.getNil(); + byte[] data = fetchBytes(buf, pos, len); + + if (callback_object != null) { + if (((RubyObject) callback_object).respondsTo("on_body")) { + ThreadContext context = callback_object.getRuntime().getCurrentContext(); + ret = callback_object.callMethod(context, "on_body", + RubyString.newString(runtime, new ByteList(data, UTF8, false))); + } + } else if (on_body != null) { + ThreadContext context = on_body.getRuntime().getCurrentContext(); + ret = on_body.callMethod(context, "call", RubyString.newString(runtime, new ByteList(data, UTF8, false))); + } + + if (ret == stopSym) { + throw new StopException(); + } else { + return 0; + } + } + }; + } + + private void init() { + this.parser = new HTTPParser(); + this.parser.HTTP_PARSER_STRICT = true; + this.headers = null; + + this.requestUrl = runtime.getNil(); + this.requestPath = runtime.getNil(); + this.queryString = runtime.getNil(); + this.fragment = runtime.getNil(); + + this.upgradeData = runtime.getNil(); + } + + @JRubyMethod(name = "initialize") + public IRubyObject initialize() { + return this; + } + + @JRubyMethod(name = "initialize") + public IRubyObject initialize(IRubyObject arg) { + callback_object = arg; + return initialize(); + } + + @JRubyMethod(name = "initialize") + public IRubyObject initialize(IRubyObject arg, IRubyObject arg2) { + header_value_type = arg2; + return initialize(arg); + } + + @JRubyMethod(name = "on_message_begin=") + public IRubyObject set_on_message_begin(IRubyObject cb) { + on_message_begin = cb; + return cb; + } + + @JRubyMethod(name = "on_headers_complete=") + public IRubyObject set_on_headers_complete(IRubyObject cb) { + on_headers_complete = cb; + return cb; + } + + @JRubyMethod(name = "on_body=") + public IRubyObject set_on_body(IRubyObject cb) { + on_body = cb; + return cb; + } + + @JRubyMethod(name = "on_message_complete=") + public IRubyObject set_on_message_complete(IRubyObject cb) { + on_message_complete = cb; + return cb; + } + + @JRubyMethod(name = "<<") + public IRubyObject execute(IRubyObject data) { + RubyString str = (RubyString) data; + ByteList byteList = str.getByteList(); + ByteBuffer buf = ByteBuffer.wrap(byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize()); + boolean stopped = false; + + try { + this.parser.execute(this.settings, buf); + } catch (HTTPException e) { + throw new RaiseException(runtime, eParserError, e.getMessage(), true); + } catch (StopException e) { + stopped = true; + } + + if (parser.getUpgrade()) { + byte[] upData = fetchBytes(buf, buf.position(), buf.limit() - buf.position()); + if (runtime.is1_9() || runtime.is2_0()) { + ((RubyString) upgradeData).cat(upData, 0, upData.length, UTF8); + } else { + ((RubyString) upgradeData).cat(upData); + } + } else if (buf.hasRemaining() && !completed) { + if (!stopped) + throw new RaiseException(runtime, eParserError, "Could not parse data entirely", true); + } + + return RubyNumeric.int2fix(runtime, buf.position()); + } + + @JRubyMethod(name = "keep_alive?") + public IRubyObject shouldKeepAlive() { + return runtime.newBoolean(parser.shouldKeepAlive()); + } + + @JRubyMethod(name = "upgrade?") + public IRubyObject shouldUpgrade() { + return runtime.newBoolean(parser.getUpgrade()); + } + + @JRubyMethod(name = "http_major") + public IRubyObject httpMajor() { + if (parser.getMajor() == 0 && parser.getMinor() == 0) + return runtime.getNil(); + else + return RubyNumeric.int2fix(runtime, parser.getMajor()); + } + + @JRubyMethod(name = "http_minor") + public IRubyObject httpMinor() { + if (parser.getMajor() == 0 && parser.getMinor() == 0) + return runtime.getNil(); + else + return RubyNumeric.int2fix(runtime, parser.getMinor()); + } + + @JRubyMethod(name = "http_version") + public IRubyObject httpVersion() { + if (parser.getMajor() == 0 && parser.getMinor() == 0) + return runtime.getNil(); + else + return runtime.newArray(httpMajor(), httpMinor()); + } + + @JRubyMethod(name = "http_method") + public IRubyObject httpMethod() { + HTTPMethod method = parser.getHTTPMethod(); + if (method != null) + return runtime.newString(new String(method.bytes)); + else + return runtime.getNil(); + } + + @JRubyMethod(name = "status_code") + public IRubyObject statusCode() { + int code = parser.getStatusCode(); + if (code != 0) + return RubyNumeric.int2fix(runtime, code); + else + return runtime.getNil(); + } + + @JRubyMethod(name = "headers") + public IRubyObject getHeaders() { + return headers == null ? runtime.getNil() : headers; + } + + @JRubyMethod(name = "request_url") + public IRubyObject getRequestUrl() { + return requestUrl == null ? runtime.getNil() : requestUrl; + } + + @JRubyMethod(name = "request_path") + public IRubyObject getRequestPath() { + return requestPath == null ? runtime.getNil() : requestPath; + } + + @JRubyMethod(name = "query_string") + public IRubyObject getQueryString() { + return queryString == null ? runtime.getNil() : queryString; + } + + @JRubyMethod(name = "fragment") + public IRubyObject getFragment() { + return fragment == null ? runtime.getNil() : fragment; + } + + @JRubyMethod(name = "header_value_type") + public IRubyObject getHeaderValueType() { + return header_value_type == null ? runtime.getNil() : header_value_type; + } + + @JRubyMethod(name = "header_value_type=") + public IRubyObject set_header_value_type(IRubyObject val) { + String valString = val.toString(); + if (valString != "mixed" && valString != "arrays" && valString != "strings") { + throw runtime.newArgumentError("Invalid header value type"); + } + header_value_type = val; + return val; + } + + @JRubyMethod(name = "upgrade_data") + public IRubyObject upgradeData() { + return upgradeData == null ? runtime.getNil() : upgradeData; + } + + @JRubyMethod(name = "reset!") + public IRubyObject reset() { + init(); + return runtime.getTrue(); + } + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ruby_http_parser.c b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ruby_http_parser.c new file mode 100644 index 0000000..5650652 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/ruby_http_parser.c @@ -0,0 +1,515 @@ +#include "ruby.h" +#include "ext_help.h" +#include "ryah_http_parser.h" + +#define GET_WRAPPER(N, from) ParserWrapper *N = (ParserWrapper *)(from)->data; +#define HASH_CAT(h, k, ptr, len) \ + do { \ + VALUE __v = rb_hash_aref(h, k); \ + if (__v != Qnil) { \ + rb_str_cat(__v, ptr, len); \ + } else { \ + rb_hash_aset(h, k, rb_str_new(ptr, len)); \ + } \ + } while(0) + +typedef struct ParserWrapper { + ryah_http_parser parser; + + VALUE request_url; + + VALUE headers; + + VALUE upgrade_data; + + VALUE on_message_begin; + VALUE on_headers_complete; + VALUE on_body; + VALUE on_message_complete; + + VALUE callback_object; + VALUE stopped; + VALUE completed; + + VALUE header_value_type; + + VALUE last_field_name; + VALUE curr_field_name; + + enum ryah_http_parser_type type; +} ParserWrapper; + +void ParserWrapper_init(ParserWrapper *wrapper) { + ryah_http_parser_init(&wrapper->parser, wrapper->type); + wrapper->parser.status_code = 0; + wrapper->parser.http_major = 0; + wrapper->parser.http_minor = 0; + + wrapper->request_url = Qnil; + + wrapper->upgrade_data = Qnil; + + wrapper->headers = Qnil; + wrapper->completed = Qfalse; + + wrapper->last_field_name = Qnil; + wrapper->curr_field_name = Qnil; +} + +void ParserWrapper_mark(void *data) { + if(data) { + ParserWrapper *wrapper = (ParserWrapper *) data; + rb_gc_mark_maybe(wrapper->request_url); + rb_gc_mark_maybe(wrapper->upgrade_data); + rb_gc_mark_maybe(wrapper->headers); + rb_gc_mark_maybe(wrapper->on_message_begin); + rb_gc_mark_maybe(wrapper->on_headers_complete); + rb_gc_mark_maybe(wrapper->on_body); + rb_gc_mark_maybe(wrapper->on_message_complete); + rb_gc_mark_maybe(wrapper->callback_object); + rb_gc_mark_maybe(wrapper->last_field_name); + rb_gc_mark_maybe(wrapper->curr_field_name); + } +} + +void ParserWrapper_free(void *data) { + if(data) { + free(data); + } +} + +static VALUE cParser; +static VALUE cRequestParser; +static VALUE cResponseParser; + +static VALUE eParserError; + +static ID Icall; +static ID Ion_message_begin; +static ID Ion_headers_complete; +static ID Ion_body; +static ID Ion_message_complete; + +static VALUE Sstop; +static VALUE Sreset; +static VALUE Sarrays; +static VALUE Sstrings; +static VALUE Smixed; + +/** Callbacks **/ + +int on_message_begin(ryah_http_parser *parser) { + GET_WRAPPER(wrapper, parser); + + wrapper->request_url = rb_str_new2(""); + wrapper->headers = rb_hash_new(); + wrapper->upgrade_data = rb_str_new2(""); + + VALUE ret = Qnil; + + if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_message_begin)) { + ret = rb_funcall(wrapper->callback_object, Ion_message_begin, 0); + } else if (wrapper->on_message_begin != Qnil) { + ret = rb_funcall(wrapper->on_message_begin, Icall, 0); + } + + if (ret == Sstop) { + wrapper->stopped = Qtrue; + return -1; + } else { + return 0; + } +} + +int on_url(ryah_http_parser *parser, const char *at, size_t length) { + GET_WRAPPER(wrapper, parser); + rb_str_cat(wrapper->request_url, at, length); + return 0; +} + +int on_header_field(ryah_http_parser *parser, const char *at, size_t length) { + GET_WRAPPER(wrapper, parser); + + if (wrapper->curr_field_name == Qnil) { + wrapper->last_field_name = Qnil; + wrapper->curr_field_name = rb_str_new(at, length); + } else { + rb_str_cat(wrapper->curr_field_name, at, length); + } + + return 0; +} + +int on_header_value(ryah_http_parser *parser, const char *at, size_t length) { + GET_WRAPPER(wrapper, parser); + + int new_field = 0; + VALUE current_value; + + if (wrapper->last_field_name == Qnil) { + new_field = 1; + wrapper->last_field_name = wrapper->curr_field_name; + wrapper->curr_field_name = Qnil; + } + + current_value = rb_hash_aref(wrapper->headers, wrapper->last_field_name); + + if (new_field == 1) { + if (current_value == Qnil) { + if (wrapper->header_value_type == Sarrays) { + rb_hash_aset(wrapper->headers, wrapper->last_field_name, rb_ary_new3(1, rb_str_new2(""))); + } else { + rb_hash_aset(wrapper->headers, wrapper->last_field_name, rb_str_new2("")); + } + } else { + if (wrapper->header_value_type == Smixed) { + if (TYPE(current_value) == T_STRING) { + rb_hash_aset(wrapper->headers, wrapper->last_field_name, rb_ary_new3(2, current_value, rb_str_new2(""))); + } else { + rb_ary_push(current_value, rb_str_new2("")); + } + } else if (wrapper->header_value_type == Sarrays) { + rb_ary_push(current_value, rb_str_new2("")); + } else { + rb_str_cat(current_value, ", ", 2); + } + } + current_value = rb_hash_aref(wrapper->headers, wrapper->last_field_name); + } + + if (TYPE(current_value) == T_ARRAY) { + current_value = rb_ary_entry(current_value, -1); + } + + rb_str_cat(current_value, at, length); + + return 0; +} + +int on_headers_complete(ryah_http_parser *parser) { + GET_WRAPPER(wrapper, parser); + + VALUE ret = Qnil; + + if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_headers_complete)) { + ret = rb_funcall(wrapper->callback_object, Ion_headers_complete, 1, wrapper->headers); + } else if (wrapper->on_headers_complete != Qnil) { + ret = rb_funcall(wrapper->on_headers_complete, Icall, 1, wrapper->headers); + } + + if (ret == Sstop) { + wrapper->stopped = Qtrue; + return -1; + } else if (ret == Sreset){ + return 1; + } else { + return 0; + } +} + +int on_body(ryah_http_parser *parser, const char *at, size_t length) { + GET_WRAPPER(wrapper, parser); + + VALUE ret = Qnil; + + if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_body)) { + ret = rb_funcall(wrapper->callback_object, Ion_body, 1, rb_str_new(at, length)); + } else if (wrapper->on_body != Qnil) { + ret = rb_funcall(wrapper->on_body, Icall, 1, rb_str_new(at, length)); + } + + if (ret == Sstop) { + wrapper->stopped = Qtrue; + return -1; + } else { + return 0; + } +} + +int on_message_complete(ryah_http_parser *parser) { + GET_WRAPPER(wrapper, parser); + + VALUE ret = Qnil; + wrapper->completed = Qtrue; + + if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_message_complete)) { + ret = rb_funcall(wrapper->callback_object, Ion_message_complete, 0); + } else if (wrapper->on_message_complete != Qnil) { + ret = rb_funcall(wrapper->on_message_complete, Icall, 0); + } + + if (ret == Sstop) { + wrapper->stopped = Qtrue; + return -1; + } else { + return 0; + } +} + +static ryah_http_parser_settings settings = { + .on_message_begin = on_message_begin, + .on_url = on_url, + .on_header_field = on_header_field, + .on_header_value = on_header_value, + .on_headers_complete = on_headers_complete, + .on_body = on_body, + .on_message_complete = on_message_complete +}; + +VALUE Parser_alloc_by_type(VALUE klass, enum ryah_http_parser_type type) { + ParserWrapper *wrapper = ALLOC_N(ParserWrapper, 1); + wrapper->type = type; + wrapper->parser.data = wrapper; + + wrapper->on_message_begin = Qnil; + wrapper->on_headers_complete = Qnil; + wrapper->on_body = Qnil; + wrapper->on_message_complete = Qnil; + + wrapper->callback_object = Qnil; + + ParserWrapper_init(wrapper); + + return Data_Wrap_Struct(klass, ParserWrapper_mark, ParserWrapper_free, wrapper); +} + +VALUE Parser_alloc(VALUE klass) { + return Parser_alloc_by_type(klass, HTTP_BOTH); +} + +VALUE RequestParser_alloc(VALUE klass) { + return Parser_alloc_by_type(klass, HTTP_REQUEST); +} + +VALUE ResponseParser_alloc(VALUE klass) { + return Parser_alloc_by_type(klass, HTTP_RESPONSE); +} + +VALUE Parser_strict_p(VALUE klass) { + return HTTP_PARSER_STRICT == 1 ? Qtrue : Qfalse; +} + +VALUE Parser_initialize(int argc, VALUE *argv, VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + wrapper->header_value_type = rb_iv_get(CLASS_OF(self), "@default_header_value_type"); + + if (argc == 1) { + wrapper->callback_object = argv[0]; + } + + if (argc == 2) { + wrapper->callback_object = argv[0]; + wrapper->header_value_type = argv[1]; + } + + return self; +} + +VALUE Parser_execute(VALUE self, VALUE data) { + ParserWrapper *wrapper = NULL; + + Check_Type(data, T_STRING); + char *ptr = RSTRING_PTR(data); + long len = RSTRING_LEN(data); + + DATA_GET(self, ParserWrapper, wrapper); + + wrapper->stopped = Qfalse; + size_t nparsed = ryah_http_parser_execute(&wrapper->parser, &settings, ptr, len); + + if (wrapper->parser.upgrade) { + if (RTEST(wrapper->stopped)) + nparsed += 1; + + rb_str_cat(wrapper->upgrade_data, ptr + nparsed, len - nparsed); + + } else if (nparsed != (size_t)len) { + if (!RTEST(wrapper->stopped) && !RTEST(wrapper->completed)) + rb_raise(eParserError, "Could not parse data entirely (%zu != %zu)", nparsed, len); + else + nparsed += 1; // error states fail on the current character + } + + return INT2FIX(nparsed); +} + +VALUE Parser_set_on_message_begin(VALUE self, VALUE callback) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + wrapper->on_message_begin = callback; + return callback; +} + +VALUE Parser_set_on_headers_complete(VALUE self, VALUE callback) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + wrapper->on_headers_complete = callback; + return callback; +} + +VALUE Parser_set_on_body(VALUE self, VALUE callback) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + wrapper->on_body = callback; + return callback; +} + +VALUE Parser_set_on_message_complete(VALUE self, VALUE callback) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + wrapper->on_message_complete = callback; + return callback; +} + +VALUE Parser_keep_alive_p(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + return http_should_keep_alive(&wrapper->parser) == 1 ? Qtrue : Qfalse; +} + +VALUE Parser_upgrade_p(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + return wrapper->parser.upgrade ? Qtrue : Qfalse; +} + +VALUE Parser_http_version(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + if (wrapper->parser.http_major == 0 && wrapper->parser.http_minor == 0) + return Qnil; + else + return rb_ary_new3(2, INT2FIX(wrapper->parser.http_major), INT2FIX(wrapper->parser.http_minor)); +} + +VALUE Parser_http_major(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + if (wrapper->parser.http_major == 0 && wrapper->parser.http_minor == 0) + return Qnil; + else + return INT2FIX(wrapper->parser.http_major); +} + +VALUE Parser_http_minor(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + if (wrapper->parser.http_major == 0 && wrapper->parser.http_minor == 0) + return Qnil; + else + return INT2FIX(wrapper->parser.http_minor); +} + +VALUE Parser_http_method(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + if (wrapper->parser.type == HTTP_REQUEST) + return rb_str_new2(http_method_str(wrapper->parser.method)); + else + return Qnil; +} + +VALUE Parser_status_code(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + if (wrapper->parser.status_code) + return INT2FIX(wrapper->parser.status_code); + else + return Qnil; +} + +#define DEFINE_GETTER(name) \ + VALUE Parser_##name(VALUE self) { \ + ParserWrapper *wrapper = NULL; \ + DATA_GET(self, ParserWrapper, wrapper); \ + return wrapper->name; \ + } + +DEFINE_GETTER(request_url); +DEFINE_GETTER(headers); +DEFINE_GETTER(upgrade_data); +DEFINE_GETTER(header_value_type); + +VALUE Parser_set_header_value_type(VALUE self, VALUE val) { + if (val != Sarrays && val != Sstrings && val != Smixed) { + rb_raise(rb_eArgError, "Invalid header value type"); + } + + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + wrapper->header_value_type = val; + return wrapper->header_value_type; +} + +VALUE Parser_reset(VALUE self) { + ParserWrapper *wrapper = NULL; + DATA_GET(self, ParserWrapper, wrapper); + + ParserWrapper_init(wrapper); + + return Qtrue; +} + +void Init_ruby_http_parser() { + VALUE mHTTP = rb_define_module("HTTP"); + cParser = rb_define_class_under(mHTTP, "Parser", rb_cObject); + cRequestParser = rb_define_class_under(mHTTP, "RequestParser", cParser); + cResponseParser = rb_define_class_under(mHTTP, "ResponseParser", cParser); + + eParserError = rb_define_class_under(cParser, "Error", rb_eIOError); + Icall = rb_intern("call"); + Ion_message_begin = rb_intern("on_message_begin"); + Ion_headers_complete = rb_intern("on_headers_complete"); + Ion_body = rb_intern("on_body"); + Ion_message_complete = rb_intern("on_message_complete"); + Sstop = ID2SYM(rb_intern("stop")); + Sreset = ID2SYM(rb_intern("reset")); + + Sarrays = ID2SYM(rb_intern("arrays")); + Sstrings = ID2SYM(rb_intern("strings")); + Smixed = ID2SYM(rb_intern("mixed")); + + rb_define_alloc_func(cParser, Parser_alloc); + rb_define_alloc_func(cRequestParser, RequestParser_alloc); + rb_define_alloc_func(cResponseParser, ResponseParser_alloc); + + rb_define_singleton_method(cParser, "strict?", Parser_strict_p, 0); + rb_define_method(cParser, "initialize", Parser_initialize, -1); + + rb_define_method(cParser, "on_message_begin=", Parser_set_on_message_begin, 1); + rb_define_method(cParser, "on_headers_complete=", Parser_set_on_headers_complete, 1); + rb_define_method(cParser, "on_body=", Parser_set_on_body, 1); + rb_define_method(cParser, "on_message_complete=", Parser_set_on_message_complete, 1); + rb_define_method(cParser, "<<", Parser_execute, 1); + + rb_define_method(cParser, "keep_alive?", Parser_keep_alive_p, 0); + rb_define_method(cParser, "upgrade?", Parser_upgrade_p, 0); + + rb_define_method(cParser, "http_version", Parser_http_version, 0); + rb_define_method(cParser, "http_major", Parser_http_major, 0); + rb_define_method(cParser, "http_minor", Parser_http_minor, 0); + + rb_define_method(cParser, "http_method", Parser_http_method, 0); + rb_define_method(cParser, "status_code", Parser_status_code, 0); + + rb_define_method(cParser, "request_url", Parser_request_url, 0); + rb_define_method(cParser, "headers", Parser_headers, 0); + rb_define_method(cParser, "upgrade_data", Parser_upgrade_data, 0); + rb_define_method(cParser, "header_value_type", Parser_header_value_type, 0); + rb_define_method(cParser, "header_value_type=", Parser_set_header_value_type, 1); + + rb_define_method(cParser, "reset!", Parser_reset, 0); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/.gitkeep b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS new file mode 100644 index 0000000..abe99de --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS @@ -0,0 +1,32 @@ +# Authors ordered by first contribution. +Ryan Dahl +Jeremy Hinegardner +Sergey Shepelev +Joe Damato +tomika +Phoenix Sol +Cliff Frey +Ewen Cheslack-Postava +Santiago Gala +Tim Becker +Jeff Terrace +Ben Noordhuis +Nathan Rajlich +Mark Nottingham +Aman Gupta +Tim Becker +Sean Cunningham +Peter Griess +Salman Haq +Cliff Frey +Jon Kolb +Fouad Mardini +Paul Querna +Felix Geisendörfer +koichik +Andre Caron +Ivo Raisr +James McLaughlin +David Gwynne +LE ROUX Thomas +Randy Rizun diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT new file mode 100644 index 0000000..a0ae8dc --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT @@ -0,0 +1,48 @@ +Copyright 2010 Tim Becker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +--- END OF LICENSE + +This code mainly based on code with the following license: + + +http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright +Igor Sysoev. + +Additional changes are licensed under the same terms as NGINX and +copyright Joyent, Inc. and other Node contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/README.md b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/README.md new file mode 100644 index 0000000..0a6a432 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/README.md @@ -0,0 +1,183 @@ +HTTP Parser +=========== + +This is a parser for HTTP written in Java, based quite heavily on +the Ryan Dahl's C Version: `http-parser` available here: + + http://github.com/ry/http-parser + +It parses both requests and responses. The parser is designed to be used +in performance HTTP applications. + +Features: + + * No dependencies (probably won't be able to keep it up) + * Handles persistent streams (keep-alive). + * Decodes chunked encoding. + * Upgrade support + +The parser extracts the following information from HTTP messages: + + * Header fields and values + * Content-Length + * Request method + * Response status code + * Transfer-Encoding + * HTTP version + * Request URL + * Message body + +Building +-------- + +use `ant compile|test|jar` + +Usage +----- + + TODO: in the present form, usage of the Java version of the parser + shouldn't be too difficult to figure out for someone familiar with the + C version. + + More documentation will follow shortly, in case you're looking for an + easy to use http library, this lib is probably not what you are + looking for anyway ... + + All text after this paragraph (and most of the text above it) are from + the original C version of the README and are currently only here for + reference. In case you encounter any difficulties, find bugs, need + help or have suggestions, feel free to contact me at + (tim.becker@kuriositaet.de). + + +One `http_parser` object is used per TCP connection. Initialize the struct +using `http_parser_init()` and set the callbacks. That might look something +like this for a request parser: + + http_parser_settings settings; + settings.on_path = my_path_callback; + settings.on_header_field = my_header_field_callback; + /* ... */ + + http_parser *parser = malloc(sizeof(http_parser)); + http_parser_init(parser, HTTP_REQUEST); + parser->data = my_socket; + +When data is received on the socket execute the parser and check for errors. + + size_t len = 80*1024, nparsed; + char buf[len]; + ssize_t recved; + + recved = recv(fd, buf, len, 0); + + if (recved < 0) { + /* Handle error. */ + } + + /* Start up / continue the parser. + * Note we pass recved==0 to signal that EOF has been recieved. + */ + nparsed = http_parser_execute(parser, &settings, buf, recved); + + if (parser->upgrade) { + /* handle new protocol */ + } else if (nparsed != recved) { + /* Handle error. Usually just close the connection. */ + } + +HTTP needs to know where the end of the stream is. For example, sometimes +servers send responses without Content-Length and expect the client to +consume input (for the body) until EOF. To tell http_parser about EOF, give +`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors +can still be encountered during an EOF, so one must still be prepared +to receive them. + +Scalar valued message information such as `status_code`, `method`, and the +HTTP version are stored in the parser structure. This data is only +temporally stored in `http_parser` and gets reset on each new message. If +this information is needed later, copy it out of the structure during the +`headers_complete` callback. + +The parser decodes the transfer-encoding for both requests and responses +transparently. That is, a chunked encoding is decoded before being sent to +the on_body callback. + + +The Special Problem of Upgrade +------------------------------ + +HTTP supports upgrading the connection to a different protocol. An +increasingly common example of this is the Web Socket protocol which sends +a request like + + GET /demo HTTP/1.1 + Upgrade: WebSocket + Connection: Upgrade + Host: example.com + Origin: http://example.com + WebSocket-Protocol: sample + +followed by non-HTTP data. + +(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more +information the Web Socket protocol.) + +To support this, the parser will treat this as a normal HTTP message without a +body. Issuing both on_headers_complete and on_message_complete callbacks. However +http_parser_execute() will stop parsing at the end of the headers and return. + +The user is expected to check if `parser->upgrade` has been set to 1 after +`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied +offset by the return value of `http_parser_execute()`. + + +Callbacks +--------- + +During the `http_parser_execute()` call, the callbacks set in +`http_parser_settings` will be executed. The parser maintains state and +never looks behind, so buffering the data is not necessary. If you need to +save certain data for later usage, you can do that from the callbacks. + +There are two types of callbacks: + +* notification `typedef int (*http_cb) (http_parser*);` + Callbacks: on_message_begin, on_headers_complete, on_message_complete. +* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);` + Callbacks: (requests only) on_uri, + (common) on_header_field, on_header_value, on_body; + +Callbacks must return 0 on success. Returning a non-zero value indicates +error to the parser, making it exit immediately. + +In case you parse HTTP message in chunks (i.e. `read()` request line +from socket, parse, read half headers, parse, etc) your data callbacks +may be called more than once. Http-parser guarantees that data pointer is only +valid for the lifetime of callback. You can also `read()` into a heap allocated +buffer to avoid copying memory around if this fits your application. + +Reading headers may be a tricky task if you read/parse headers partially. +Basically, you need to remember whether last header callback was field or value +and apply following logic: + + (on_header_field and on_header_value shortened to on_h_*) + ------------------------ ------------ -------------------------------------------- + | State (prev. callback) | Callback | Description/action | + ------------------------ ------------ -------------------------------------------- + | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | + | | | into it | + ------------------------ ------------ -------------------------------------------- + | value | on_h_field | New header started. | + | | | Copy current name,value buffers to headers | + | | | list and allocate new buffer for new name | + ------------------------ ------------ -------------------------------------------- + | field | on_h_field | Previous name continues. Reallocate name | + | | | buffer and append callback data to it | + ------------------------ ------------ -------------------------------------------- + | field | on_h_value | Value for current header started. Allocate | + | | | new buffer and copy callback data to it | + ------------------------ ------------ -------------------------------------------- + | value | on_h_value | Value continues. Reallocate value buffer | + | | | and append callback data to it | + ------------------------ ------------ -------------------------------------------- diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/TODO b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/TODO new file mode 100644 index 0000000..eb46a08 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/TODO @@ -0,0 +1,28 @@ +decide how to handle errs per default: + - ry: "set state to dead", return `read` + - current: call on_error w/ details, if no on_error handler set, + throw Exception, else call on_error and behave like orig... + +some tests from test.c left to port + (scan ...) +documentation + +hi level callback interface +eventloop +state() as a function (?) + - perhaps, the idea being to be able to log/debug better... +more tests + - in particular, port available c tests +impl bits of servlet api. + +DONE + +Sun Jul 18 12:19:18 CEST 2010 + +error handling + - consider callback based error handling and the current highlevel + "nice" logging moved to high level http impl. + - use Exceptions "ProtocolException"? + +better testing + - no junit to avoid dependencies diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/build.xml b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/build.xml new file mode 100755 index 0000000..d2c6af4 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c new file mode 100644 index 0000000..e961ae8 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c @@ -0,0 +1,2175 @@ +/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev + * + * Additional changes are licensed under the same terms as NGINX and + * copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "http_parser.h" +#include +#include +#include +#include +#include +#include + +#ifndef ULLONG_MAX +# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#ifndef BIT_AT +# define BIT_AT(a, i) \ + (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ + (1 << ((unsigned int) (i) & 7)))) +#endif + +#ifndef ELEM_AT +# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) +#endif + +#define SET_ERRNO(e) \ +do { \ + parser->http_errno = (e); \ +} while(0) + + +/* Run the notify callback FOR, returning ER if it fails */ +#define CALLBACK_NOTIFY_(FOR, ER) \ +do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser)) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + \ + /* We either errored above or got paused; get out */ \ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ + return (ER); \ + } \ + } \ +} while (0) + +/* Run the notify callback FOR and consume the current byte */ +#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) + +/* Run the notify callback FOR and don't consume the current byte */ +#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) + +/* Run data callback FOR with LEN bytes, returning ER if it fails */ +#define CALLBACK_DATA_(FOR, LEN, ER) \ +do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (FOR##_mark) { \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + \ + /* We either errored above or got paused; get out */ \ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ + return (ER); \ + } \ + } \ + FOR##_mark = NULL; \ + } \ +} while (0) + +/* Run the data callback FOR and consume the current byte */ +#define CALLBACK_DATA(FOR) \ + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) + +/* Run the data callback FOR and don't consume the current byte */ +#define CALLBACK_DATA_NOADVANCE(FOR) \ + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) + +/* Set the mark FOR; non-destructive if mark is already set */ +#define MARK(FOR) \ +do { \ + if (!FOR##_mark) { \ + FOR##_mark = p; \ + } \ +} while (0) + + +#define PROXY_CONNECTION "proxy-connection" +#define CONNECTION "connection" +#define CONTENT_LENGTH "content-length" +#define TRANSFER_ENCODING "transfer-encoding" +#define UPGRADE "upgrade" +#define CHUNKED "chunked" +#define KEEP_ALIVE "keep-alive" +#define CLOSE "close" + + +static const char *method_strings[] = + { +#define XX(num, name, string) #string, + HTTP_METHOD_MAP(XX) +#undef XX + }; + + +/* Tokens as defined by rfc 2616. Also lowercases them. + * token = 1* + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + */ +static const char tokens[256] = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0, '!', 0, '#', '$', '%', '&', '\'', +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 0, 0, '*', '+', 0, '-', '.', 0, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + '0', '1', '2', '3', '4', '5', '6', '7', +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + '8', '9', 0, 0, 0, 0, 0, 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 'x', 'y', 'z', 0, 0, 0, '^', '_', +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 'x', 'y', 'z', 0, '|', 0, '~', 0 }; + + +static const int8_t unhex[256] = + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; + + +#if HTTP_PARSER_STRICT +# define T(v) 0 +#else +# define T(v) v +#endif + + +static const uint8_t normal_url_char[32] = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; + +#undef T + +enum state + { s_dead = 1 /* important that this is > 0 */ + + , s_start_req_or_res + , s_res_or_resp_H + , s_start_res + , s_res_H + , s_res_HT + , s_res_HTT + , s_res_HTTP + , s_res_first_http_major + , s_res_http_major + , s_res_first_http_minor + , s_res_http_minor + , s_res_first_status_code + , s_res_status_code + , s_res_status + , s_res_line_almost_done + + , s_start_req + + , s_req_method + , s_req_spaces_before_url + , s_req_schema + , s_req_schema_slash + , s_req_schema_slash_slash + , s_req_server_start + , s_req_server + , s_req_server_with_at + , s_req_path + , s_req_query_string_start + , s_req_query_string + , s_req_fragment_start + , s_req_fragment + , s_req_http_start + , s_req_http_H + , s_req_http_HT + , s_req_http_HTT + , s_req_http_HTTP + , s_req_first_http_major + , s_req_http_major + , s_req_first_http_minor + , s_req_http_minor + , s_req_line_almost_done + + , s_header_field_start + , s_header_field + , s_header_value_start + , s_header_value + , s_header_value_lws + + , s_header_almost_done + + , s_chunk_size_start + , s_chunk_size + , s_chunk_parameters + , s_chunk_size_almost_done + + , s_headers_almost_done + , s_headers_done + + /* Important: 's_headers_done' must be the last 'header' state. All + * states beyond this must be 'body' states. It is used for overflow + * checking. See the PARSING_HEADER() macro. + */ + + , s_chunk_data + , s_chunk_data_almost_done + , s_chunk_data_done + + , s_body_identity + , s_body_identity_eof + + , s_message_done + }; + + +#define PARSING_HEADER(state) (state <= s_headers_done) + + +enum header_states + { h_general = 0 + , h_C + , h_CO + , h_CON + + , h_matching_connection + , h_matching_proxy_connection + , h_matching_content_length + , h_matching_transfer_encoding + , h_matching_upgrade + + , h_connection + , h_content_length + , h_transfer_encoding + , h_upgrade + + , h_matching_transfer_encoding_chunked + , h_matching_connection_keep_alive + , h_matching_connection_close + + , h_transfer_encoding_chunked + , h_connection_keep_alive + , h_connection_close + }; + +enum http_host_state + { + s_http_host_dead = 1 + , s_http_userinfo_start + , s_http_userinfo + , s_http_host_start + , s_http_host_v6_start + , s_http_host + , s_http_host_v6 + , s_http_host_v6_end + , s_http_host_port_start + , s_http_host_port +}; + +/* Macros for character classes; depends on strict-mode */ +#define CR '\r' +#define LF '\n' +#define LOWER(c) (unsigned char)(c | 0x20) +#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') +#define IS_NUM(c) ((c) >= '0' && (c) <= '9') +#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) +#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) +#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ + (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ + (c) == ')') +#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ + (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ + (c) == '$' || (c) == ',') + +#if HTTP_PARSER_STRICT +#define TOKEN(c) (tokens[(unsigned char)c]) +#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') +#else +#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) +#define IS_URL_CHAR(c) \ + (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) +#define IS_HOST_CHAR(c) \ + (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') +#endif + + +#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) + + +#if HTTP_PARSER_STRICT +# define STRICT_CHECK(cond) \ +do { \ + if (cond) { \ + SET_ERRNO(HPE_STRICT); \ + goto error; \ + } \ +} while (0) +# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) +#else +# define STRICT_CHECK(cond) +# define NEW_MESSAGE() start_state +#endif + + +/* Map errno values to strings for human-readable output */ +#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, +static struct { + const char *name; + const char *description; +} http_strerror_tab[] = { + HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) +}; +#undef HTTP_STRERROR_GEN + +int http_message_needs_eof(const http_parser *parser); + +/* Our URL parser. + * + * This is designed to be shared by http_parser_execute() for URL validation, + * hence it has a state transition + byte-for-byte interface. In addition, it + * is meant to be embedded in http_parser_parse_url(), which does the dirty + * work of turning state transitions URL components for its API. + * + * This function should only be invoked with non-space characters. It is + * assumed that the caller cares about (and can detect) the transition between + * URL and non-URL states by looking for these. + */ +static enum state +parse_url_char(enum state s, const char ch) +{ + if (ch == ' ' || ch == '\r' || ch == '\n') { + return s_dead; + } + +#if HTTP_PARSER_STRICT + if (ch == '\t' || ch == '\f') { + return s_dead; + } +#endif + + switch (s) { + case s_req_spaces_before_url: + /* Proxied requests are followed by scheme of an absolute URI (alpha). + * All methods except CONNECT are followed by '/' or '*'. + */ + + if (ch == '/' || ch == '*') { + return s_req_path; + } + + if (IS_ALPHA(ch)) { + return s_req_schema; + } + + break; + + case s_req_schema: + if (IS_ALPHA(ch)) { + return s; + } + + if (ch == ':') { + return s_req_schema_slash; + } + + break; + + case s_req_schema_slash: + if (ch == '/') { + return s_req_schema_slash_slash; + } + + break; + + case s_req_schema_slash_slash: + if (ch == '/') { + return s_req_server_start; + } + + break; + + case s_req_server_with_at: + if (ch == '@') { + return s_dead; + } + + /* FALLTHROUGH */ + case s_req_server_start: + case s_req_server: + if (ch == '/') { + return s_req_path; + } + + if (ch == '?') { + return s_req_query_string_start; + } + + if (ch == '@') { + return s_req_server_with_at; + } + + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { + return s_req_server; + } + + break; + + case s_req_path: + if (IS_URL_CHAR(ch)) { + return s; + } + + switch (ch) { + case '?': + return s_req_query_string_start; + + case '#': + return s_req_fragment_start; + } + + break; + + case s_req_query_string_start: + case s_req_query_string: + if (IS_URL_CHAR(ch)) { + return s_req_query_string; + } + + switch (ch) { + case '?': + /* allow extra '?' in query string */ + return s_req_query_string; + + case '#': + return s_req_fragment_start; + } + + break; + + case s_req_fragment_start: + if (IS_URL_CHAR(ch)) { + return s_req_fragment; + } + + switch (ch) { + case '?': + return s_req_fragment; + + case '#': + return s; + } + + break; + + case s_req_fragment: + if (IS_URL_CHAR(ch)) { + return s; + } + + switch (ch) { + case '?': + case '#': + return s; + } + + break; + + default: + break; + } + + /* We should never fall out of the switch above unless there's an error */ + return s_dead; +} + +size_t http_parser_execute (http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len) +{ + char c, ch; + int8_t unhex_val; + const char *p = data; + const char *header_field_mark = 0; + const char *header_value_mark = 0; + const char *url_mark = 0; + const char *body_mark = 0; + + /* We're in an error state. Don't bother doing anything. */ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { + return 0; + } + + if (len == 0) { + switch (parser->state) { + case s_body_identity_eof: + /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if + * we got paused. + */ + CALLBACK_NOTIFY_NOADVANCE(message_complete); + return 0; + + case s_dead: + case s_start_req_or_res: + case s_start_res: + case s_start_req: + return 0; + + default: + SET_ERRNO(HPE_INVALID_EOF_STATE); + return 1; + } + } + + + if (parser->state == s_header_field) + header_field_mark = data; + if (parser->state == s_header_value) + header_value_mark = data; + switch (parser->state) { + case s_req_path: + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + case s_req_server: + case s_req_server_with_at: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + url_mark = data; + break; + } + + for (p=data; p != data + len; p++) { + ch = *p; + + if (PARSING_HEADER(parser->state)) { + ++parser->nread; + /* Buffer overflow attack */ + if (parser->nread > HTTP_MAX_HEADER_SIZE) { + SET_ERRNO(HPE_HEADER_OVERFLOW); + goto error; + } + } + + reexecute_byte: + switch (parser->state) { + + case s_dead: + /* this state is used after a 'Connection: close' message + * the parser will error out if it reads another message + */ + if (ch == CR || ch == LF) + break; + + SET_ERRNO(HPE_CLOSED_CONNECTION); + goto error; + + case s_start_req_or_res: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (ch == 'H') { + parser->state = s_res_or_resp_H; + + CALLBACK_NOTIFY(message_begin); + } else { + parser->type = HTTP_REQUEST; + parser->state = s_start_req; + goto reexecute_byte; + } + + break; + } + + case s_res_or_resp_H: + if (ch == 'T') { + parser->type = HTTP_RESPONSE; + parser->state = s_res_HT; + } else { + if (ch != 'E') { + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + parser->type = HTTP_REQUEST; + parser->method = HTTP_HEAD; + parser->index = 2; + parser->state = s_req_method; + } + break; + + case s_start_res: + { + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + switch (ch) { + case 'H': + parser->state = s_res_H; + break; + + case CR: + case LF: + break; + + default: + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + CALLBACK_NOTIFY(message_begin); + break; + } + + case s_res_H: + STRICT_CHECK(ch != 'T'); + parser->state = s_res_HT; + break; + + case s_res_HT: + STRICT_CHECK(ch != 'T'); + parser->state = s_res_HTT; + break; + + case s_res_HTT: + STRICT_CHECK(ch != 'P'); + parser->state = s_res_HTTP; + break; + + case s_res_HTTP: + STRICT_CHECK(ch != '/'); + parser->state = s_res_first_http_major; + break; + + case s_res_first_http_major: + if (ch < '0' || ch > '9') { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + parser->state = s_res_http_major; + break; + + /* major HTTP version or dot */ + case s_res_http_major: + { + if (ch == '.') { + parser->state = s_res_first_http_minor; + break; + } + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + /* first digit of minor HTTP version */ + case s_res_first_http_minor: + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + parser->state = s_res_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_res_http_minor: + { + if (ch == ' ') { + parser->state = s_res_first_status_code; + break; + } + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + case s_res_first_status_code: + { + if (!IS_NUM(ch)) { + if (ch == ' ') { + break; + } + + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + parser->status_code = ch - '0'; + parser->state = s_res_status_code; + break; + } + + case s_res_status_code: + { + if (!IS_NUM(ch)) { + switch (ch) { + case ' ': + parser->state = s_res_status; + break; + case CR: + parser->state = s_res_line_almost_done; + break; + case LF: + parser->state = s_header_field_start; + break; + default: + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + break; + } + + parser->status_code *= 10; + parser->status_code += ch - '0'; + + if (parser->status_code > 999) { + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + + break; + } + + case s_res_status: + /* the human readable status. e.g. "NOT FOUND" + * we are not humans so just ignore this */ + if (ch == CR) { + parser->state = s_res_line_almost_done; + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + break; + } + break; + + case s_res_line_almost_done: + STRICT_CHECK(ch != LF); + parser->state = s_header_field_start; + CALLBACK_NOTIFY(status_complete); + break; + + case s_start_req: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (!IS_ALPHA(ch)) { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + parser->method = (enum http_method) 0; + parser->index = 1; + switch (ch) { + case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; + case 'D': parser->method = HTTP_DELETE; break; + case 'G': parser->method = HTTP_GET; break; + case 'H': parser->method = HTTP_HEAD; break; + case 'L': parser->method = HTTP_LOCK; break; + case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; + case 'N': parser->method = HTTP_NOTIFY; break; + case 'O': parser->method = HTTP_OPTIONS; break; + case 'P': parser->method = HTTP_POST; + /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ + break; + case 'R': parser->method = HTTP_REPORT; break; + case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; + case 'T': parser->method = HTTP_TRACE; break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; + default: + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + parser->state = s_req_method; + + CALLBACK_NOTIFY(message_begin); + + break; + } + + case s_req_method: + { + const char *matcher; + if (ch == '\0') { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + matcher = method_strings[parser->method]; + if (ch == ' ' && matcher[parser->index] == '\0') { + parser->state = s_req_spaces_before_url; + } else if (ch == matcher[parser->index]) { + ; /* nada */ + } else if (parser->method == HTTP_CONNECT) { + if (parser->index == 1 && ch == 'H') { + parser->method = HTTP_CHECKOUT; + } else if (parser->index == 2 && ch == 'P') { + parser->method = HTTP_COPY; + } else { + goto error; + } + } else if (parser->method == HTTP_MKCOL) { + if (parser->index == 1 && ch == 'O') { + parser->method = HTTP_MOVE; + } else if (parser->index == 1 && ch == 'E') { + parser->method = HTTP_MERGE; + } else if (parser->index == 1 && ch == '-') { + parser->method = HTTP_MSEARCH; + } else if (parser->index == 2 && ch == 'A') { + parser->method = HTTP_MKACTIVITY; + } else { + goto error; + } + } else if (parser->method == HTTP_SUBSCRIBE) { + if (parser->index == 1 && ch == 'E') { + parser->method = HTTP_SEARCH; + } else { + goto error; + } + } else if (parser->index == 1 && parser->method == HTTP_POST) { + if (ch == 'R') { + parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ + } else if (ch == 'U') { + parser->method = HTTP_PUT; /* or HTTP_PURGE */ + } else if (ch == 'A') { + parser->method = HTTP_PATCH; + } else { + goto error; + } + } else if (parser->index == 2) { + if (parser->method == HTTP_PUT) { + if (ch == 'R') parser->method = HTTP_PURGE; + } else if (parser->method == HTTP_UNLOCK) { + if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE; + } + } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { + parser->method = HTTP_PROPPATCH; + } else { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + ++parser->index; + break; + } + + case s_req_spaces_before_url: + { + if (ch == ' ') break; + + MARK(url); + if (parser->method == HTTP_CONNECT) { + parser->state = s_req_server_start; + } + + parser->state = parse_url_char((enum state)parser->state, ch); + if (parser->state == s_dead) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + + break; + } + + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + { + switch (ch) { + /* No whitespace allowed here */ + case ' ': + case CR: + case LF: + SET_ERRNO(HPE_INVALID_URL); + goto error; + default: + parser->state = parse_url_char((enum state)parser->state, ch); + if (parser->state == s_dead) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + + break; + } + + case s_req_server: + case s_req_server_with_at: + case s_req_path: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + { + switch (ch) { + case ' ': + parser->state = s_req_http_start; + CALLBACK_DATA(url); + break; + case CR: + case LF: + parser->http_major = 0; + parser->http_minor = 9; + parser->state = (ch == CR) ? + s_req_line_almost_done : + s_header_field_start; + CALLBACK_DATA(url); + break; + default: + parser->state = parse_url_char((enum state)parser->state, ch); + if (parser->state == s_dead) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + break; + } + + case s_req_http_start: + switch (ch) { + case 'H': + parser->state = s_req_http_H; + break; + case ' ': + break; + default: + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + break; + + case s_req_http_H: + STRICT_CHECK(ch != 'T'); + parser->state = s_req_http_HT; + break; + + case s_req_http_HT: + STRICT_CHECK(ch != 'T'); + parser->state = s_req_http_HTT; + break; + + case s_req_http_HTT: + STRICT_CHECK(ch != 'P'); + parser->state = s_req_http_HTTP; + break; + + case s_req_http_HTTP: + STRICT_CHECK(ch != '/'); + parser->state = s_req_first_http_major; + break; + + /* first digit of major HTTP version */ + case s_req_first_http_major: + if (ch < '1' || ch > '9') { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + parser->state = s_req_http_major; + break; + + /* major HTTP version or dot */ + case s_req_http_major: + { + if (ch == '.') { + parser->state = s_req_first_http_minor; + break; + } + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + /* first digit of minor HTTP version */ + case s_req_first_http_minor: + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + parser->state = s_req_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_req_http_minor: + { + if (ch == CR) { + parser->state = s_req_line_almost_done; + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + break; + } + + /* XXX allow spaces after digit? */ + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + /* end of request line */ + case s_req_line_almost_done: + { + if (ch != LF) { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } + + parser->state = s_header_field_start; + break; + } + + case s_header_field_start: + { + if (ch == CR) { + parser->state = s_headers_almost_done; + break; + } + + if (ch == LF) { + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + parser->state = s_headers_almost_done; + goto reexecute_byte; + } + + c = TOKEN(ch); + + if (!c) { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + MARK(header_field); + + parser->index = 0; + parser->state = s_header_field; + + switch (c) { + case 'c': + parser->header_state = h_C; + break; + + case 'p': + parser->header_state = h_matching_proxy_connection; + break; + + case 't': + parser->header_state = h_matching_transfer_encoding; + break; + + case 'u': + parser->header_state = h_matching_upgrade; + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_field: + { + c = TOKEN(ch); + + if (c) { + switch (parser->header_state) { + case h_general: + break; + + case h_C: + parser->index++; + parser->header_state = (c == 'o' ? h_CO : h_general); + break; + + case h_CO: + parser->index++; + parser->header_state = (c == 'n' ? h_CON : h_general); + break; + + case h_CON: + parser->index++; + switch (c) { + case 'n': + parser->header_state = h_matching_connection; + break; + case 't': + parser->header_state = h_matching_content_length; + break; + default: + parser->header_state = h_general; + break; + } + break; + + /* connection */ + + case h_matching_connection: + parser->index++; + if (parser->index > sizeof(CONNECTION)-1 + || c != CONNECTION[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CONNECTION)-2) { + parser->header_state = h_connection; + } + break; + + /* proxy-connection */ + + case h_matching_proxy_connection: + parser->index++; + if (parser->index > sizeof(PROXY_CONNECTION)-1 + || c != PROXY_CONNECTION[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { + parser->header_state = h_connection; + } + break; + + /* content-length */ + + case h_matching_content_length: + parser->index++; + if (parser->index > sizeof(CONTENT_LENGTH)-1 + || c != CONTENT_LENGTH[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { + parser->header_state = h_content_length; + } + break; + + /* transfer-encoding */ + + case h_matching_transfer_encoding: + parser->index++; + if (parser->index > sizeof(TRANSFER_ENCODING)-1 + || c != TRANSFER_ENCODING[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { + parser->header_state = h_transfer_encoding; + } + break; + + /* upgrade */ + + case h_matching_upgrade: + parser->index++; + if (parser->index > sizeof(UPGRADE)-1 + || c != UPGRADE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(UPGRADE)-2) { + parser->header_state = h_upgrade; + } + break; + + case h_connection: + case h_content_length: + case h_transfer_encoding: + case h_upgrade: + if (ch != ' ') parser->header_state = h_general; + break; + + default: + assert(0 && "Unknown header_state"); + break; + } + break; + } + + if (ch == ':') { + parser->state = s_header_value_start; + CALLBACK_DATA(header_field); + break; + } + + if (ch == CR) { + parser->state = s_header_almost_done; + CALLBACK_DATA(header_field); + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + CALLBACK_DATA(header_field); + break; + } + + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + case s_header_value_start: + { + if (ch == ' ' || ch == '\t') break; + + MARK(header_value); + + parser->state = s_header_value; + parser->index = 0; + + if (ch == CR) { + parser->header_state = h_general; + parser->state = s_header_almost_done; + CALLBACK_DATA(header_value); + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + CALLBACK_DATA(header_value); + break; + } + + c = LOWER(ch); + + switch (parser->header_state) { + case h_upgrade: + parser->flags |= F_UPGRADE; + parser->header_state = h_general; + break; + + case h_transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if ('c' == c) { + parser->header_state = h_matching_transfer_encoding_chunked; + } else { + parser->header_state = h_general; + } + break; + + case h_content_length: + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = ch - '0'; + break; + + case h_connection: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') { + parser->header_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (c == 'c') { + parser->header_state = h_matching_connection_close; + } else { + parser->header_state = h_general; + } + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_value: + { + + if (ch == CR) { + parser->state = s_header_almost_done; + CALLBACK_DATA(header_value); + break; + } + + if (ch == LF) { + parser->state = s_header_almost_done; + CALLBACK_DATA_NOADVANCE(header_value); + goto reexecute_byte; + } + + c = LOWER(ch); + + switch (parser->header_state) { + case h_general: + break; + + case h_connection: + case h_transfer_encoding: + assert(0 && "Shouldn't get here."); + break; + + case h_content_length: + { + uint64_t t; + + if (ch == ' ') break; + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + t = parser->content_length; + t *= 10; + t += ch - '0'; + + /* Overflow? */ + if (t < parser->content_length || t == ULLONG_MAX) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = t; + break; + } + + /* Transfer-Encoding: chunked */ + case h_matching_transfer_encoding_chunked: + parser->index++; + if (parser->index > sizeof(CHUNKED)-1 + || c != CHUNKED[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CHUNKED)-2) { + parser->header_state = h_transfer_encoding_chunked; + } + break; + + /* looking for 'Connection: keep-alive' */ + case h_matching_connection_keep_alive: + parser->index++; + if (parser->index > sizeof(KEEP_ALIVE)-1 + || c != KEEP_ALIVE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(KEEP_ALIVE)-2) { + parser->header_state = h_connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case h_matching_connection_close: + parser->index++; + if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CLOSE)-2) { + parser->header_state = h_connection_close; + } + break; + + case h_transfer_encoding_chunked: + case h_connection_keep_alive: + case h_connection_close: + if (ch != ' ') parser->header_state = h_general; + break; + + default: + parser->state = s_header_value; + parser->header_state = h_general; + break; + } + break; + } + + case s_header_almost_done: + { + STRICT_CHECK(ch != LF); + + parser->state = s_header_value_lws; + + switch (parser->header_state) { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + default: + break; + } + + break; + } + + case s_header_value_lws: + { + if (ch == ' ' || ch == '\t') + parser->state = s_header_value_start; + else + { + parser->state = s_header_field_start; + goto reexecute_byte; + } + break; + } + + case s_headers_almost_done: + { + STRICT_CHECK(ch != LF); + + if (parser->flags & F_TRAILING) { + /* End of a chunked request */ + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + break; + } + + parser->state = s_headers_done; + + /* Set this here so that on_headers_complete() callbacks can see it */ + parser->upgrade = + (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); + + /* Here we call the headers_complete callback. This is somewhat + * different than other callbacks because if the user returns 1, we + * will interpret that as saying that this message has no body. This + * is needed for the annoying case of recieving a response to a HEAD + * request. + * + * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so + * we have to simulate it by handling a change in errno below. + */ + if (settings->on_headers_complete) { + switch (settings->on_headers_complete(parser)) { + case 0: + break; + + case 1: + parser->flags |= F_SKIPBODY; + break; + + default: + SET_ERRNO(HPE_CB_headers_complete); + return p - data; /* Error */ + } + } + + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { + return p - data; + } + + goto reexecute_byte; + } + + case s_headers_done: + { + STRICT_CHECK(ch != LF); + + parser->nread = 0; + + /* Exit, the rest of the connect is in a different protocol. */ + if (parser->upgrade) { + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + return (p - data) + 1; + } + + if (parser->flags & F_SKIPBODY) { + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + parser->state = s_chunk_size_start; + } else { + if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + } else if (parser->content_length != ULLONG_MAX) { + /* Content-Length header given and non-zero */ + parser->state = s_body_identity; + } else { + if (parser->type == HTTP_REQUEST || + !http_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + } else { + /* Read body until EOF */ + parser->state = s_body_identity_eof; + } + } + } + + break; + } + + case s_body_identity: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t) ((data + len) - p)); + + assert(parser->content_length != 0 + && parser->content_length != ULLONG_MAX); + + /* The difference between advancing content_length and p is because + * the latter will automaticaly advance on the next loop iteration. + * Further, if content_length ends up at 0, we want to see the last + * byte again for our message complete callback. + */ + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; + + if (parser->content_length == 0) { + parser->state = s_message_done; + + /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. + * + * The alternative to doing this is to wait for the next byte to + * trigger the data callback, just as in every other case. The + * problem with this is that this makes it difficult for the test + * harness to distinguish between complete-on-EOF and + * complete-on-length. It's not clear that this distinction is + * important for applications, but let's keep it for now. + */ + CALLBACK_DATA_(body, p - body_mark + 1, p - data); + goto reexecute_byte; + } + + break; + } + + /* read until EOF */ + case s_body_identity_eof: + MARK(body); + p = data + len - 1; + + break; + + case s_message_done: + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + break; + + case s_chunk_size_start: + { + assert(parser->nread == 1); + assert(parser->flags & F_CHUNKED); + + unhex_val = unhex[(unsigned char)ch]; + if (unhex_val == -1) { + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } + + parser->content_length = unhex_val; + parser->state = s_chunk_size; + break; + } + + case s_chunk_size: + { + uint64_t t; + + assert(parser->flags & F_CHUNKED); + + if (ch == CR) { + parser->state = s_chunk_size_almost_done; + break; + } + + unhex_val = unhex[(unsigned char)ch]; + + if (unhex_val == -1) { + if (ch == ';' || ch == ' ') { + parser->state = s_chunk_parameters; + break; + } + + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } + + t = parser->content_length; + t *= 16; + t += unhex_val; + + /* Overflow? */ + if (t < parser->content_length || t == ULLONG_MAX) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = t; + break; + } + + case s_chunk_parameters: + { + assert(parser->flags & F_CHUNKED); + /* just ignore this shit. TODO check for overflow */ + if (ch == CR) { + parser->state = s_chunk_size_almost_done; + break; + } + break; + } + + case s_chunk_size_almost_done: + { + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + + parser->nread = 0; + + if (parser->content_length == 0) { + parser->flags |= F_TRAILING; + parser->state = s_header_field_start; + } else { + parser->state = s_chunk_data; + } + break; + } + + case s_chunk_data: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t) ((data + len) - p)); + + assert(parser->flags & F_CHUNKED); + assert(parser->content_length != 0 + && parser->content_length != ULLONG_MAX); + + /* See the explanation in s_body_identity for why the content + * length and data pointers are managed this way. + */ + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; + + if (parser->content_length == 0) { + parser->state = s_chunk_data_almost_done; + } + + break; + } + + case s_chunk_data_almost_done: + assert(parser->flags & F_CHUNKED); + assert(parser->content_length == 0); + STRICT_CHECK(ch != CR); + parser->state = s_chunk_data_done; + CALLBACK_DATA(body); + break; + + case s_chunk_data_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + parser->nread = 0; + parser->state = s_chunk_size_start; + break; + + default: + assert(0 && "unhandled state"); + SET_ERRNO(HPE_INVALID_INTERNAL_STATE); + goto error; + } + } + + /* Run callbacks for any marks that we have leftover after we ran our of + * bytes. There should be at most one of these set, so it's OK to invoke + * them in series (unset marks will not result in callbacks). + * + * We use the NOADVANCE() variety of callbacks here because 'p' has already + * overflowed 'data' and this allows us to correct for the off-by-one that + * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' + * value that's in-bounds). + */ + + assert(((header_field_mark ? 1 : 0) + + (header_value_mark ? 1 : 0) + + (url_mark ? 1 : 0) + + (body_mark ? 1 : 0)) <= 1); + + CALLBACK_DATA_NOADVANCE(header_field); + CALLBACK_DATA_NOADVANCE(header_value); + CALLBACK_DATA_NOADVANCE(url); + CALLBACK_DATA_NOADVANCE(body); + + return len; + +error: + if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { + SET_ERRNO(HPE_UNKNOWN); + } + + return (p - data); +} + + +/* Does the parser need to see an EOF to find the end of the message? */ +int +http_message_needs_eof (const http_parser *parser) +{ + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + parser->flags & F_SKIPBODY) { /* response to a HEAD request */ + return 0; + } + + if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { + return 0; + } + + return 1; +} + + +int +http_should_keep_alive (const http_parser *parser) +{ + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !http_message_needs_eof(parser); +} + + +const char * +http_method_str (enum http_method m) +{ + return ELEM_AT(method_strings, m, ""); +} + + +void +http_parser_init (http_parser *parser, enum http_parser_type t) +{ + void *data = parser->data; /* preserve application data */ + memset(parser, 0, sizeof(*parser)); + parser->data = data; + parser->type = t; + parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); + parser->http_errno = HPE_OK; +} + +const char * +http_errno_name(enum http_errno err) { + assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); + return http_strerror_tab[err].name; +} + +const char * +http_errno_description(enum http_errno err) { + assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); + return http_strerror_tab[err].description; +} + +static enum http_host_state +http_parse_host_char(enum http_host_state s, const char ch) { + switch(s) { + case s_http_userinfo: + case s_http_userinfo_start: + if (ch == '@') { + return s_http_host_start; + } + + if (IS_USERINFO_CHAR(ch)) { + return s_http_userinfo; + } + break; + + case s_http_host_start: + if (ch == '[') { + return s_http_host_v6_start; + } + + if (IS_HOST_CHAR(ch)) { + return s_http_host; + } + + break; + + case s_http_host: + if (IS_HOST_CHAR(ch)) { + return s_http_host; + } + + /* FALLTHROUGH */ + case s_http_host_v6_end: + if (ch == ':') { + return s_http_host_port_start; + } + + break; + + case s_http_host_v6: + if (ch == ']') { + return s_http_host_v6_end; + } + + /* FALLTHROUGH */ + case s_http_host_v6_start: + if (IS_HEX(ch) || ch == ':' || ch == '.') { + return s_http_host_v6; + } + + break; + + case s_http_host_port: + case s_http_host_port_start: + if (IS_NUM(ch)) { + return s_http_host_port; + } + + break; + + default: + break; + } + return s_http_host_dead; +} + +static int +http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { + enum http_host_state s; + + const char *p; + size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; + + u->field_data[UF_HOST].len = 0; + + s = found_at ? s_http_userinfo_start : s_http_host_start; + + for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { + enum http_host_state new_s = http_parse_host_char(s, *p); + + if (new_s == s_http_host_dead) { + return 1; + } + + switch(new_s) { + case s_http_host: + if (s != s_http_host) { + u->field_data[UF_HOST].off = p - buf; + } + u->field_data[UF_HOST].len++; + break; + + case s_http_host_v6: + if (s != s_http_host_v6) { + u->field_data[UF_HOST].off = p - buf; + } + u->field_data[UF_HOST].len++; + break; + + case s_http_host_port: + if (s != s_http_host_port) { + u->field_data[UF_PORT].off = p - buf; + u->field_data[UF_PORT].len = 0; + u->field_set |= (1 << UF_PORT); + } + u->field_data[UF_PORT].len++; + break; + + case s_http_userinfo: + if (s != s_http_userinfo) { + u->field_data[UF_USERINFO].off = p - buf ; + u->field_data[UF_USERINFO].len = 0; + u->field_set |= (1 << UF_USERINFO); + } + u->field_data[UF_USERINFO].len++; + break; + + default: + break; + } + s = new_s; + } + + /* Make sure we don't end somewhere unexpected */ + switch (s) { + case s_http_host_start: + case s_http_host_v6_start: + case s_http_host_v6: + case s_http_host_port_start: + case s_http_userinfo: + case s_http_userinfo_start: + return 1; + default: + break; + } + + return 0; +} + +int +http_parser_parse_url(const char *buf, size_t buflen, int is_connect, + struct http_parser_url *u) +{ + enum state s; + const char *p; + enum http_parser_url_fields uf, old_uf; + int found_at = 0; + + u->port = u->field_set = 0; + s = is_connect ? s_req_server_start : s_req_spaces_before_url; + uf = old_uf = UF_MAX; + + for (p = buf; p < buf + buflen; p++) { + s = parse_url_char(s, *p); + + /* Figure out the next field that we're operating on */ + switch (s) { + case s_dead: + return 1; + + /* Skip delimeters */ + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + case s_req_query_string_start: + case s_req_fragment_start: + continue; + + case s_req_schema: + uf = UF_SCHEMA; + break; + + case s_req_server_with_at: + found_at = 1; + + /* FALLTROUGH */ + case s_req_server: + uf = UF_HOST; + break; + + case s_req_path: + uf = UF_PATH; + break; + + case s_req_query_string: + uf = UF_QUERY; + break; + + case s_req_fragment: + uf = UF_FRAGMENT; + break; + + default: + assert(!"Unexpected state"); + return 1; + } + + /* Nothing's changed; soldier on */ + if (uf == old_uf) { + u->field_data[uf].len++; + continue; + } + + u->field_data[uf].off = p - buf; + u->field_data[uf].len = 1; + + u->field_set |= (1 << uf); + old_uf = uf; + } + + /* host must be present if there is a schema */ + /* parsing http:///toto will fail */ + if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { + if (http_parse_host(buf, u, found_at) != 0) { + return 1; + } + } + + /* CONNECT requests can only contain "hostname:port" */ + if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { + return 1; + } + + if (u->field_set & (1 << UF_PORT)) { + /* Don't bother with endp; we've already validated the string */ + unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); + + /* Ports have a max value of 2^16 */ + if (v > 0xffff) { + return 1; + } + + u->port = (uint16_t) v; + } + + return 0; +} + +void +http_parser_pause(http_parser *parser, int paused) { + /* Users should only be pausing/unpausing a parser that is not in an error + * state. In non-debug builds, there's not much that we can do about this + * other than ignore it. + */ + if (HTTP_PARSER_ERRNO(parser) == HPE_OK || + HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { + SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); + } else { + assert(0 && "Attempting to pause parser in error state"); + } +} + +int +http_body_is_final(const struct http_parser *parser) { + return parser->state == s_message_done; +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp new file mode 100644 index 0000000..c6eada7 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp @@ -0,0 +1,79 @@ +# This file is used with the GYP meta build system. +# http://code.google.com/p/gyp/ +# To build try this: +# svn co http://gyp.googlecode.com/svn/trunk gyp +# ./gyp/gyp -f make --depth=`pwd` http_parser.gyp +# ./out/Debug/test +{ + 'target_defaults': { + 'default_configuration': 'Debug', + 'configurations': { + # TODO: hoist these out and put them somewhere common, because + # RuntimeLibrary MUST MATCH across the entire project + 'Debug': { + 'defines': [ 'DEBUG', '_DEBUG' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 1, # static debug + }, + }, + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 0, # static release + }, + }, + } + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + }, + 'VCLibrarianTool': { + }, + 'VCLinkerTool': { + 'GenerateDebugInformation': 'true', + }, + }, + 'conditions': [ + ['OS == "win"', { + 'defines': [ + 'WIN32' + ], + }] + ], + }, + + 'targets': [ + { + 'target_name': 'http_parser', + 'type': 'static_library', + 'include_dirs': [ '.' ], + 'direct_dependent_settings': { + 'include_dirs': [ '.' ], + }, + 'defines': [ 'HTTP_PARSER_STRICT=0' ], + 'sources': [ './http_parser.c', ], + 'conditions': [ + ['OS=="win"', { + 'msvs_settings': { + 'VCCLCompilerTool': { + # Compile as C++. http_parser.c is actually C99, but C++ is + # close enough in this case. + 'CompileAs': 2, + }, + }, + }] + ], + }, + + { + 'target_name': 'test', + 'type': 'executable', + 'dependencies': [ 'http_parser' ], + 'sources': [ 'test.c' ] + } + ] +} + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h new file mode 100644 index 0000000..2fff4bd --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h @@ -0,0 +1,304 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef http_parser_h +#define http_parser_h +#ifdef __cplusplus +extern "C" { +#endif + +#define HTTP_PARSER_VERSION_MAJOR 2 +#define HTTP_PARSER_VERSION_MINOR 0 + +#include +#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) +#include +#include +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run + * faster + */ +#ifndef HTTP_PARSER_STRICT +# define HTTP_PARSER_STRICT 1 +#endif + +/* Maximium header size allowed */ +#define HTTP_MAX_HEADER_SIZE (80*1024) + + +typedef struct http_parser http_parser; +typedef struct http_parser_settings http_parser_settings; + + +/* Callbacks should return non-zero to indicate an error. The parser will + * then halt execution. + * + * The one exception is on_headers_complete. In a HTTP_RESPONSE parser + * returning '1' from on_headers_complete will tell the parser that it + * should not expect a body. This is used when receiving a response to a + * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: + * chunked' headers that indicate the presence of a body. + * + * http_data_cb does not return data chunks. It will be call arbitrarally + * many times for each string. E.G. you might get 10 callbacks for "on_url" + * each providing just a few characters more data. + */ +typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); +typedef int (*http_cb) (http_parser*); + + +/* Request Methods */ +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + /* pathological */ \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + /* webdav */ \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + /* subversion */ \ + XX(16, REPORT, REPORT) \ + XX(17, MKACTIVITY, MKACTIVITY) \ + XX(18, CHECKOUT, CHECKOUT) \ + XX(19, MERGE, MERGE) \ + /* upnp */ \ + XX(20, MSEARCH, M-SEARCH) \ + XX(21, NOTIFY, NOTIFY) \ + XX(22, SUBSCRIBE, SUBSCRIBE) \ + XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ + /* RFC-5789 */ \ + XX(24, PATCH, PATCH) \ + XX(25, PURGE, PURGE) \ + +enum http_method + { +#define XX(num, name, string) HTTP_##name = num, + HTTP_METHOD_MAP(XX) +#undef XX + }; + + +enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; + + +/* Flag values for http_parser.flags field */ +enum flags + { F_CHUNKED = 1 << 0 + , F_CONNECTION_KEEP_ALIVE = 1 << 1 + , F_CONNECTION_CLOSE = 1 << 2 + , F_TRAILING = 1 << 3 + , F_UPGRADE = 1 << 4 + , F_SKIPBODY = 1 << 5 + }; + + +/* Map for errno-related constants + * + * The provided argument should be a macro that takes 2 arguments. + */ +#define HTTP_ERRNO_MAP(XX) \ + /* No error */ \ + XX(OK, "success") \ + \ + /* Callback-related errors */ \ + XX(CB_message_begin, "the on_message_begin callback failed") \ + XX(CB_status_complete, "the on_status_complete callback failed") \ + XX(CB_url, "the on_url callback failed") \ + XX(CB_header_field, "the on_header_field callback failed") \ + XX(CB_header_value, "the on_header_value callback failed") \ + XX(CB_headers_complete, "the on_headers_complete callback failed") \ + XX(CB_body, "the on_body callback failed") \ + XX(CB_message_complete, "the on_message_complete callback failed") \ + \ + /* Parsing-related errors */ \ + XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ + XX(HEADER_OVERFLOW, \ + "too many header bytes seen; overflow detected") \ + XX(CLOSED_CONNECTION, \ + "data received after completed connection: close message") \ + XX(INVALID_VERSION, "invalid HTTP version") \ + XX(INVALID_STATUS, "invalid HTTP status code") \ + XX(INVALID_METHOD, "invalid HTTP method") \ + XX(INVALID_URL, "invalid URL") \ + XX(INVALID_HOST, "invalid host") \ + XX(INVALID_PORT, "invalid port") \ + XX(INVALID_PATH, "invalid path") \ + XX(INVALID_QUERY_STRING, "invalid query string") \ + XX(INVALID_FRAGMENT, "invalid fragment") \ + XX(LF_EXPECTED, "LF character expected") \ + XX(INVALID_HEADER_TOKEN, "invalid character in header") \ + XX(INVALID_CONTENT_LENGTH, \ + "invalid character in content-length header") \ + XX(INVALID_CHUNK_SIZE, \ + "invalid character in chunk size header") \ + XX(INVALID_CONSTANT, "invalid constant string") \ + XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ + XX(STRICT, "strict mode assertion failed") \ + XX(PAUSED, "parser is paused") \ + XX(UNKNOWN, "an unknown error occurred") + + +/* Define HPE_* values for each errno value above */ +#define HTTP_ERRNO_GEN(n, s) HPE_##n, +enum http_errno { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) +}; +#undef HTTP_ERRNO_GEN + + +/* Get an http_errno value from an http_parser */ +#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) + + +struct http_parser { + /** PRIVATE **/ + unsigned char type : 2; /* enum http_parser_type */ + unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ + unsigned char state; /* enum state from http_parser.c */ + unsigned char header_state; /* enum header_state from http_parser.c */ + unsigned char index; /* index into current matcher */ + + uint32_t nread; /* # bytes read in various scenarios */ + uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ + + /** READ-ONLY **/ + unsigned short http_major; + unsigned short http_minor; + unsigned short status_code; /* responses only */ + unsigned char method; /* requests only */ + unsigned char http_errno : 7; + + /* 1 = Upgrade header was present and the parser has exited because of that. + * 0 = No upgrade header present. + * Should be checked when http_parser_execute() returns in addition to + * error checking. + */ + unsigned char upgrade : 1; + + /** PUBLIC **/ + void *data; /* A pointer to get hook to the "connection" or "socket" object */ +}; + + +struct http_parser_settings { + http_cb on_message_begin; + http_data_cb on_url; + http_cb on_status_complete; + http_data_cb on_header_field; + http_data_cb on_header_value; + http_cb on_headers_complete; + http_data_cb on_body; + http_cb on_message_complete; +}; + + +enum http_parser_url_fields + { UF_SCHEMA = 0 + , UF_HOST = 1 + , UF_PORT = 2 + , UF_PATH = 3 + , UF_QUERY = 4 + , UF_FRAGMENT = 5 + , UF_USERINFO = 6 + , UF_MAX = 7 + }; + + +/* Result structure for http_parser_parse_url(). + * + * Callers should index into field_data[] with UF_* values iff field_set + * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and + * because we probably have padding left over), we convert any port to + * a uint16_t. + */ +struct http_parser_url { + uint16_t field_set; /* Bitmask of (1 << UF_*) values */ + uint16_t port; /* Converted UF_PORT string */ + + struct { + uint16_t off; /* Offset into buffer in which field starts */ + uint16_t len; /* Length of run in buffer */ + } field_data[UF_MAX]; +}; + + +void http_parser_init(http_parser *parser, enum http_parser_type type); + + +size_t http_parser_execute(http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len); + + +/* If http_should_keep_alive() in the on_headers_complete or + * on_message_complete callback returns 0, then this should be + * the last message on the connection. + * If you are the server, respond with the "Connection: close" header. + * If you are the client, close the connection. + */ +int http_should_keep_alive(const http_parser *parser); + +/* Returns a string version of the HTTP method. */ +const char *http_method_str(enum http_method m); + +/* Return a string name of the given error */ +const char *http_errno_name(enum http_errno err); + +/* Return a string description of the given error */ +const char *http_errno_description(enum http_errno err); + +/* Parse a URL; return nonzero on failure */ +int http_parser_parse_url(const char *buf, size_t buflen, + int is_connect, + struct http_parser_url *u); + +/* Pause or un-pause the parser; a nonzero value pauses */ +void http_parser_pause(http_parser *parser, int paused); + +/* Checks if this is the final chunk of the body. */ +int http_body_is_final(const http_parser *parser); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml new file mode 100644 index 0000000..741121a --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java new file mode 100644 index 0000000..774179f --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java @@ -0,0 +1,41 @@ +package http_parser; + +public class FieldData { + public int off; + public int len; + + public FieldData(){} + + public FieldData(int off, int len){ + this.off = off; + this.len = len; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FieldData fieldData = (FieldData) o; + + if (len != fieldData.len) return false; + if (off != fieldData.off) return false; + + return true; + } + + @Override + public int hashCode() { + int result = off; + result = 31 * result + len; + return result; + } + + @Override + public String toString() { + return "FieldData{" + + "off=" + off + + ", len=" + len + + '}'; + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java new file mode 100644 index 0000000..5380b0f --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java @@ -0,0 +1,8 @@ +package http_parser; + +public abstract class HTTPCallback implements http_parser.lolevel.HTTPCallback{ + public int cb (http_parser.lolevel.HTTPParser parser) { + return this.cb((HTTPParser)parser); + } + public abstract int cb (HTTPParser parser); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java new file mode 100644 index 0000000..bfe576f --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java @@ -0,0 +1,34 @@ +package http_parser; + +import java.nio.ByteBuffer; + +public abstract class HTTPDataCallback implements http_parser.lolevel.HTTPDataCallback{ + /* + Very raw and extremly foolhardy! DANGER! + The whole Buffer concept is difficult enough to grasp as it is, + we pass in a buffer with an arbitrary position. + + The interesting data is located at position pos and is len + bytes long. + + The contract of this callback is that the buffer is + returned in the state that it was passed in, so implementing + this require good citizenship, you'll need to remember the current + position, change the position to get at the data you're interested + in and then set the position back to how you found it... + + Therefore: there is an abstract implementation that implements + cb as described above, and provides a new callback + with signature @see cb(byte[], int, int) + */ + public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) { + byte [] by = new byte[len]; + int saved = buf.position(); + buf.position(pos); + buf.get(by); + buf.position(saved); + return cb((HTTPParser)p, by, 0, len); + } + + public abstract int cb(HTTPParser p, byte[] by, int pos, int len); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java new file mode 100644 index 0000000..a74206e --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java @@ -0,0 +1,12 @@ +package http_parser; + + +import java.nio.ByteBuffer; + +public abstract class HTTPErrorCallback implements http_parser.lolevel.HTTPErrorCallback{ + public void cb (http_parser.lolevel.HTTPParser parser, String mes, ByteBuffer buf, int initial_position) { + this.cb((HTTPParser)parser, Util.error(mes, buf, initial_position)); + } + + public abstract void cb(HTTPParser parser, String error); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java new file mode 100644 index 0000000..9ccaf14 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java @@ -0,0 +1,9 @@ +package http_parser; + +@SuppressWarnings("serial") +public class HTTPException extends RuntimeException { + +public HTTPException(String mes) { + super(mes); + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java new file mode 100644 index 0000000..7c080c1 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java @@ -0,0 +1,107 @@ +package http_parser; + +import java.nio.charset.Charset; + +public enum HTTPMethod { + HTTP_DELETE("DELETE")// = 0 + , HTTP_GET("GET") + , HTTP_HEAD("HEAD") + , HTTP_POST("POST") + , HTTP_PUT("PUT") + , HTTP_PATCH("PATCH") + /* pathological */ + , HTTP_CONNECT("CONNECT") + , HTTP_OPTIONS("OPTIONS") + , HTTP_TRACE("TRACE") + /* webdav */ + , HTTP_COPY("COPY") + , HTTP_LOCK("LOCK") + , HTTP_MKCOL("MKCOL") + , HTTP_MOVE("MOVE") + , HTTP_PROPFIND("PROPFIND") + , HTTP_PROPPATCH("PROPPATCH") + , HTTP_UNLOCK("UNLOCK") + , HTTP_REPORT("REPORT") + , HTTP_MKACTIVITY("MKACTIVITY") + , HTTP_CHECKOUT("CHECKOUT") + , HTTP_MERGE("MERGE") + , HTTP_MSEARCH("M-SEARCH") + , HTTP_NOTIFY("NOTIFY") + , HTTP_SUBSCRIBE("SUBSCRIBE") + , HTTP_UNSUBSCRIBE("UNSUBSCRIBE") + , HTTP_PURGE("PURGE") + ; + + private static Charset ASCII; + static { + ASCII = Charset.forName("US-ASCII");; + } + public byte[] bytes; + + HTTPMethod(String name) { + // good grief, Charlie Brown, the following is necessary because + // java is retarded: + // illegal reference to static field from initializer + // this.bytes = name.getBytes(ASCII); + // yet it's not illegal to reference static fields from + // methods called from initializer. + init(name); + } + public static HTTPMethod parse(String s) { + if ("HTTP_DELETE".equalsIgnoreCase(s)) {return HTTP_DELETE;} + else if ("DELETE".equalsIgnoreCase(s)) {return HTTP_DELETE;} + else if ("HTTP_GET".equalsIgnoreCase(s)) {return HTTP_GET;} + else if ("GET".equalsIgnoreCase(s)) {return HTTP_GET;} + else if ("HTTP_HEAD".equalsIgnoreCase(s)) {return HTTP_HEAD;} + else if ("HEAD".equalsIgnoreCase(s)) {return HTTP_HEAD;} + else if ("HTTP_POST".equalsIgnoreCase(s)) {return HTTP_POST;} + else if ("POST".equalsIgnoreCase(s)) {return HTTP_POST;} + else if ("HTTP_PUT".equalsIgnoreCase(s)) {return HTTP_PUT;} + else if ("PUT".equalsIgnoreCase(s)) {return HTTP_PUT;} + else if ("HTTP_PATCH".equalsIgnoreCase(s)) {return HTTP_PATCH;} + else if ("PATCH".equalsIgnoreCase(s)) {return HTTP_PATCH;} + else if ("HTTP_CONNECT".equalsIgnoreCase(s)) {return HTTP_CONNECT;} + else if ("CONNECT".equalsIgnoreCase(s)) {return HTTP_CONNECT;} + else if ("HTTP_OPTIONS".equalsIgnoreCase(s)) {return HTTP_OPTIONS;} + else if ("OPTIONS".equalsIgnoreCase(s)) {return HTTP_OPTIONS;} + else if ("HTTP_TRACE".equalsIgnoreCase(s)) {return HTTP_TRACE;} + else if ("TRACE".equalsIgnoreCase(s)) {return HTTP_TRACE;} + else if ("HTTP_COPY".equalsIgnoreCase(s)) {return HTTP_COPY;} + else if ("COPY".equalsIgnoreCase(s)) {return HTTP_COPY;} + else if ("HTTP_LOCK".equalsIgnoreCase(s)) {return HTTP_LOCK;} + else if ("LOCK".equalsIgnoreCase(s)) {return HTTP_LOCK;} + else if ("HTTP_MKCOL".equalsIgnoreCase(s)) {return HTTP_MKCOL;} + else if ("MKCOL".equalsIgnoreCase(s)) {return HTTP_MKCOL;} + else if ("HTTP_MOVE".equalsIgnoreCase(s)) {return HTTP_MOVE;} + else if ("MOVE".equalsIgnoreCase(s)) {return HTTP_MOVE;} + else if ("HTTP_PROPFIND".equalsIgnoreCase(s)){return HTTP_PROPFIND;} + else if ("PROPFIND".equalsIgnoreCase(s)) {return HTTP_PROPFIND;} + else if ("HTTP_PROPPATCH".equalsIgnoreCase(s)){return HTTP_PROPPATCH;} + else if ("PROPPATCH".equalsIgnoreCase(s)) {return HTTP_PROPPATCH;} + else if ("HTTP_UNLOCK".equalsIgnoreCase(s)) {return HTTP_UNLOCK;} + else if ("UNLOCK".equalsIgnoreCase(s)) {return HTTP_UNLOCK;} + else if ("HTTP_REPORT".equalsIgnoreCase(s)) {return HTTP_REPORT;} + else if ("REPORT".equalsIgnoreCase(s)){return HTTP_REPORT;} + else if ("HTTP_MKACTIVITY".equalsIgnoreCase(s)) {return HTTP_MKACTIVITY;} + else if ("MKACTIVITY".equalsIgnoreCase(s)){return HTTP_MKACTIVITY;} + else if ("HTTP_CHECKOUT".equalsIgnoreCase(s)) {return HTTP_CHECKOUT;} + else if ("CHECKOUT".equalsIgnoreCase(s)){return HTTP_CHECKOUT;} + else if ("HTTP_MERGE".equalsIgnoreCase(s)) {return HTTP_MERGE;} + else if ("MERGE".equalsIgnoreCase(s)){return HTTP_MERGE;} + else if ("HTTP_MSEARCH".equalsIgnoreCase(s)) {return HTTP_MSEARCH;} + else if ("M-SEARCH".equalsIgnoreCase(s)) {return HTTP_MSEARCH;} + else if ("HTTP_NOTIFY".equalsIgnoreCase(s)) {return HTTP_NOTIFY;} + else if ("NOTIFY".equalsIgnoreCase(s)) {return HTTP_NOTIFY;} + else if ("HTTP_SUBSCRIBE".equalsIgnoreCase(s)) {return HTTP_SUBSCRIBE;} + else if ("SUBSCRIBE".equalsIgnoreCase(s)) {return HTTP_SUBSCRIBE;} + else if ("HTTP_UNSUBSCRIBE".equalsIgnoreCase(s)) {return HTTP_UNSUBSCRIBE;} + else if ("UNSUBSCRIBE".equalsIgnoreCase(s)) {return HTTP_UNSUBSCRIBE;} + else if ("PATCH".equalsIgnoreCase(s)) {return HTTP_PATCH;} + else if ("PURGE".equalsIgnoreCase(s)) {return HTTP_PURGE;} + else {return null;} + } + void init (String name) { + ASCII = null == ASCII ? Charset.forName("US-ASCII") : ASCII; + this.bytes = name.getBytes(ASCII); + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java new file mode 100644 index 0000000..7ab4fb4 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java @@ -0,0 +1,36 @@ +package http_parser; + +import java.nio.ByteBuffer; + +public class HTTPParser extends http_parser.lolevel.HTTPParser { + + public HTTPParser() { super(); } + public HTTPParser(ParserType type) { super(type); } + + public int getMajor() { + return super.http_major; + } + + public int getMinor() { + return super.http_minor; + } + + public int getStatusCode() { + return super.status_code; + } + + public HTTPMethod getHTTPMethod() { + return super.method; + } + + public boolean getUpgrade() { + return super.upgrade; + } + + public boolean shouldKeepAlive() { + return super.http_should_keep_alive(); + } + public void execute(ParserSettings settings, ByteBuffer data) { + this.execute(settings.getLoLevelSettings(), data); + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java new file mode 100644 index 0000000..d371634 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java @@ -0,0 +1,76 @@ +package http_parser; + +import http_parser.lolevel.*; +import http_parser.lolevel.HTTPParser; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +/** + */ +public class HTTPParserUrl { + + public int field_set; + public int port; + + public FieldData[] field_data = new FieldData[]{ + new FieldData(0,0), + new FieldData(0,0), + new FieldData(0,0), + new FieldData(0,0), + new FieldData(0,0), + new FieldData(0,0) + }; //UF_MAX + + public HTTPParserUrl(){} + + public HTTPParserUrl(int field_set, int port, FieldData[] field_data){ + this.field_set = field_set; + this.port = port; + this.field_data = field_data; + } + + public String getFieldValue(HTTPParser.UrlFields field, ByteBuffer data) throws UnsupportedEncodingException { + FieldData fd = this.field_data[field.getIndex()]; + if(fd.off == 0 & fd.len == 0) return ""; + byte[] dst = new byte[fd.len]; + int current_pos = data.position(); + data.position(fd.off); + data.get(dst,0,fd.len); + data.position(current_pos); + String v = new String(dst, "UTF8"); + return v; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HTTPParserUrl that = (HTTPParserUrl) o; + + if (field_set != that.field_set) return false; + if (port != that.port) return false; + if (!Arrays.equals(field_data, that.field_data)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = field_set; + result = 31 * result + port; + result = 31 * result + Arrays.hashCode(field_data); + return result; + } + + @Override + public String toString() { + return "HTTPParserUrl{" + + "field_set=" + field_set + + ", port=" + port + + ", field_data=" + (field_data == null ? null : Arrays.asList(field_data)) + + '}'; + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java new file mode 100644 index 0000000..9a5e6e9 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java @@ -0,0 +1,256 @@ +package http_parser; + + + +import primitive.collection.ByteList; + +public class ParserSettings extends http_parser.lolevel.ParserSettings { + + public HTTPCallback on_message_begin; + public HTTPDataCallback on_path; + public HTTPDataCallback on_query_string; + public HTTPDataCallback on_url; + public HTTPDataCallback on_fragment; + public HTTPCallback on_status_complete; + public HTTPDataCallback on_header_field; + public HTTPDataCallback on_header_value; + + public HTTPCallback on_headers_complete; + public HTTPDataCallback on_body; + public HTTPCallback on_message_complete; + + public HTTPErrorCallback on_error; + + private HTTPCallback _on_message_begin; + private HTTPDataCallback _on_path; + private HTTPDataCallback _on_query_string; + private HTTPDataCallback _on_url; + private HTTPDataCallback _on_fragment; + private HTTPCallback _on_status_complete; + private HTTPDataCallback _on_header_field; + private HTTPDataCallback _on_header_value; + private HTTPCallback _on_headers_complete; + private HTTPDataCallback _on_body; + private HTTPCallback _on_message_complete; + private HTTPErrorCallback _on_error; + + private http_parser.lolevel.ParserSettings settings; + + protected ByteList field = new ByteList(); + protected ByteList value = new ByteList(); + protected ByteList body = new ByteList(); + + public ParserSettings() { + this.settings = new http_parser.lolevel.ParserSettings(); + createMirrorCallbacks(); + attachCallbacks(); + } + + protected http_parser.lolevel.ParserSettings getLoLevelSettings() { + return this.settings; + } + + private void createMirrorCallbacks() { + this._on_message_begin = new HTTPCallback() { + public int cb(HTTPParser p) { + if (null != ParserSettings.this.on_message_begin) { + return ParserSettings.this.on_message_begin.cb(p); + } + return 0; + } + }; + this._on_path = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + if (null != ParserSettings.this.on_path) { + return ParserSettings.this.on_path.cb(p, by, pos, len); + } + return 0; + } + }; + this._on_query_string = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + if (null != ParserSettings.this.on_query_string) { + return ParserSettings.this.on_query_string.cb(p, by, pos, len); + } + return 0; + } + }; + this._on_url = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + if (null != ParserSettings.this.on_url) { + return ParserSettings.this.on_url.cb(p, by, pos, len); + } + return 0; + } + }; + this._on_fragment = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + if (null != ParserSettings.this.on_fragment) { + return ParserSettings.this.on_fragment.cb(p, by, pos, len); + } + return 0; + } + }; + this._on_status_complete = new HTTPCallback() { + @Override + public int cb(HTTPParser p) { + if (null != ParserSettings.this.on_status_complete) { + return ParserSettings.this.on_status_complete.cb(p); + } + return 0; + } + }; + this._on_error = new HTTPErrorCallback() { + @Override + public void cb(HTTPParser parser, String error) { + if (null != ParserSettings.this.on_error) { + ParserSettings.this.on_error.cb(parser, error); + } else { + throw new HTTPException(error); + } + + } + }; + + + +// (on_header_field and on_header_value shortened to on_h_*) +// ------------------------ ------------ -------------------------------------------- +// | State (prev. callback) | Callback | Description/action | +// ------------------------ ------------ -------------------------------------------- +// | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | +// | | | into it | +// ------------------------ ------------ -------------------------------------------- +// | value | on_h_field | New header started. | +// | | | Copy current name,value buffers to headers | +// | | | list and allocate new buffer for new name | +// ------------------------ ------------ -------------------------------------------- +// | field | on_h_field | Previous name continues. Reallocate name | +// | | | buffer and append callback data to it | +// ------------------------ ------------ -------------------------------------------- +// | field | on_h_value | Value for current header started. Allocate | +// | | | new buffer and copy callback data to it | +// ------------------------ ------------ -------------------------------------------- +// | value | on_h_value | Value continues. Reallocate value buffer | +// | | | and append callback data to it | +// ------------------------ ------------ -------------------------------------------- + this._on_header_field = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + // previous value complete, call on_value with full value, reset value. + if (0 != ParserSettings.this.value.size()) { + // check we're even interested... + if (null != ParserSettings.this.on_header_value) { + byte [] valueArr = ParserSettings.this.value.toArray(); + int ret = ParserSettings.this.on_header_value.cb(p, valueArr, 0, valueArr.length); + if (0 != ret) { + return ret; + } + ParserSettings.this.value.clear(); + } + } + + if (null == ParserSettings.this.on_header_field) { + return 0; + } + + ParserSettings.this.field.addAll(by); + return 0; + } + }; + this._on_header_value = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + + // previous field complete, call on_field with full field value, reset field. + if (0 != ParserSettings.this.field.size()) { + // check we're even interested... + if (null != ParserSettings.this.on_header_field) { + byte [] fieldArr = ParserSettings.this.field.toArray(); + int ret = ParserSettings.this.on_header_field.cb(p, fieldArr, 0, fieldArr.length); + if (0 != ret) { + return ret; + } + ParserSettings.this.field.clear(); + } + } + + if (null == ParserSettings.this.on_header_value) { + return 0; + } + ParserSettings.this.value.addAll(by); + return 0; + } + }; + this._on_headers_complete = new HTTPCallback() { + @Override + public int cb(HTTPParser parser) { + // is there an uncompleted value ... ? + if (0 != ParserSettings.this.value.size()) { + // check we're even interested... + if (null != ParserSettings.this.on_header_value) { + byte [] valueArr = ParserSettings.this.value.toArray(); + int ret = ParserSettings.this.on_header_value.cb(parser, valueArr, 0, valueArr.length); + if (0 != ret) { + return ret; + } + ParserSettings.this.value.clear(); + } + } + if (null != ParserSettings.this.on_headers_complete) { + return ParserSettings.this.on_headers_complete.cb(parser); + } + return 0; + } + + }; + this._on_body = new HTTPDataCallback() { + @Override + public int cb(HTTPParser p, byte[] by, int pos, int len) { + if (null != ParserSettings.this.on_body) { + ParserSettings.this.body.addAll(by, pos, len); + } + return 0; + } + }; + + this._on_message_complete = new HTTPCallback() { + @Override + public int cb(HTTPParser parser) { + if (null != ParserSettings.this.on_body) { + byte [] body = ParserSettings.this.body.toArray(); + int ret = ParserSettings.this.on_body.cb(parser, body, 0, body.length); + if (0!=ret) { + return ret; + } + ParserSettings.this.body.clear(); + } + if (null != ParserSettings.this.on_message_complete) { + return ParserSettings.this.on_message_complete.cb(parser); + } + return 0; + } + }; + + } + + private void attachCallbacks() { + // these are certainly set, because we mirror them ... + this.settings.on_message_begin = this._on_message_begin; + this.settings.on_path = this._on_path; + this.settings.on_query_string = this._on_query_string; + this.settings.on_url = this._on_url; + this.settings.on_fragment = this._on_fragment; + this.settings.on_status_complete = this._on_status_complete; + this.settings.on_header_field = this._on_header_field; + this.settings.on_header_value = this._on_header_value; + this.settings.on_headers_complete = this._on_headers_complete; + this.settings.on_body = this._on_body; + this.settings.on_message_complete = this._on_message_complete; + this.settings.on_error = this._on_error; + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java new file mode 100644 index 0000000..a51f5b4 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java @@ -0,0 +1,13 @@ +package http_parser; + +public enum ParserType { +HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH; + + public static ParserType parse(String s) { + if ("HTTP_REQUEST".equalsIgnoreCase(s)) { return HTTP_REQUEST; } + else if ("HTTP_RESPONSE".equalsIgnoreCase(s)) { return HTTP_RESPONSE; } + else if ("HTTP_BOTH".equalsIgnoreCase(s)) { return HTTP_BOTH; } + else { return null; } + } +} + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java new file mode 100644 index 0000000..575003a --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java @@ -0,0 +1,111 @@ +package http_parser; + +import java.nio.ByteBuffer; + +public class Util { +// public static String toString(http_parser.lolevel.HTTPParser p) { +// StringBuilder builder = new StringBuilder(); +// +// // the stuff up to the break is ephermeral and only meaningful +// // while the parser is parsing. In general, this method is +// // probably only useful during debugging. +// +// builder.append("state :"); builder.append(p.state); builder.append("\n"); +// builder.append("header_state :"); builder.append(p.header_state); builder.append("\n"); +// builder.append("strict :"); builder.append(p.strict); builder.append("\n"); +// builder.append("index :"); builder.append(p.index); builder.append("\n"); +// builder.append("flags :"); builder.append(p.flags); builder.append("\n"); +// builder.append("nread :"); builder.append(p.nread); builder.append("\n"); +// builder.append("content_length :"); builder.append(p.content_length); builder.append("\n"); +// +// +// builder.append("type :"); builder.append(p.type); builder.append("\n"); +// builder.append("http_major :"); builder.append(p.http_major); builder.append("\n"); +// builder.append("http_minor :"); builder.append(p.http_minor); builder.append("\n"); +// builder.append("status_code :"); builder.append(p.status_code); builder.append("\n"); +// builder.append("method :"); builder.append(p.method); builder.append("\n"); +// builder.append("upgrade :"); builder.append(p.upgrade); builder.append("\n"); +// +// return builder.toString(); +// +// } + + public static String error (String mes, ByteBuffer b, int beginning) { + // the error message should look like this: + // + // Bla expected something, but it's not there (mes) + // GEt / HTTP 1_1 + // ............^. + // + // |----------------- 72 -------------------------| + + // This is ridiculously complicated and probably riddled with + // off-by-one errors, should be moved into high level interface. + // TODO. + + // also: need to keep track of the initial buffer position in + // execute so that we don't screw up any `mark()` that may have + // been set outside of our control to be nice. + + final int mes_width = 72; + int p = b.position(); // error position + int end = b.limit(); // this is the end + int m = end - beginning; // max mes length + + StringBuilder builder = new StringBuilder(); + int p_adj = p; + + byte [] orig = new byte[0]; + if (m <= mes_width) { + orig = new byte[m]; + b.position(beginning); + b.get(orig, 0, m); + p_adj = p-beginning; + + + } else { + // we'll need to trim bit off the beginning and/or end + orig = new byte[mes_width]; + // three possibilities: + // a.) plenty of stuff around p + // b.) plenty of stuff in front of p + // c.) plenty of stuff behind p + // CAN'T be not enough stuff aorund p in total, because + // m>meswidth (see if to this else) + + int before = p-beginning; + int after = end - p; + if ( (before > mes_width/2) && (after > mes_width/2)) { + // plenty of stuff in front of and behind error + p_adj = mes_width/2; + b.position(p - mes_width/2); + b.get(orig, 0, mes_width); + } else if (before <= mes_width/2) { + // take all of the begining. + b.position(beginning); + // and as much of the rest as possible + + b.get(orig, 0, mes_width); + + } else { + // plenty of stuff before + before = end-mes_width; + b.position(before); + p_adj = p - before; + b.get(orig, 0, mes_width); + } + } + + builder.append(new String(orig)); + builder.append("\n"); + for (int i = 0; i!= p_adj; ++i) { + builder.append("."); + } + builder.append("^"); + + + b.position(p); // restore position + return builder.toString(); + + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java new file mode 100644 index 0000000..95c29b3 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java @@ -0,0 +1,5 @@ +package http_parser.lolevel; + +public interface HTTPCallback { + public int cb (HTTPParser parser); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java new file mode 100644 index 0000000..6cad156 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java @@ -0,0 +1,25 @@ +package http_parser.lolevel; + +import java.nio.ByteBuffer; + +public interface HTTPDataCallback { + /* + very raw and extremly foolhardy! DANGER! + The whole Buffer concept is difficult enough to grasp as it is, + we pass in a buffer with an arbitrary position. + + The interesting data is located at position pos and is len + bytes long. + + The contract of this callback is that the buffer is + returned in the state that it was passed in, so implementing + this require good citizenship, you'll need to remember the current + position, change the position to get at the data you're interested + in and then set the position back to how you found it... + + //TODO: there should be an abstract implementation that implements + cb as described above, marks it final an provides a new callback + with signature cb(byte[], int, int) + */ + public int cb(HTTPParser p, ByteBuffer buf, int pos, int len); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java new file mode 100644 index 0000000..d38d9d4 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java @@ -0,0 +1,7 @@ +package http_parser.lolevel; + +import java.nio.ByteBuffer; + +public interface HTTPErrorCallback { + public void cb (HTTPParser parser, String mes, ByteBuffer buf, int initial_position); +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java new file mode 100644 index 0000000..42022ec --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java @@ -0,0 +1,2161 @@ +package http_parser.lolevel; + +import java.nio.ByteBuffer; +import http_parser.HTTPException; +import http_parser.HTTPMethod; +import http_parser.HTTPParserUrl; +import http_parser.ParserType; +import static http_parser.lolevel.HTTPParser.C.*; +import static http_parser.lolevel.HTTPParser.State.*; + +public class HTTPParser { + /* lots of unsigned chars here, not sure what + to about them, `bytes` in java suck... */ + + ParserType type; + State state; + HState header_state; + boolean strict; + + int index; + int flags; // TODO + + int nread; + long content_length; + + int p_start; // updated each call to execute to indicate where the buffer was before we began calling it. + + /** READ-ONLY **/ + public int http_major; + public int http_minor; + public int status_code; /* responses only */ + public HTTPMethod method; /* requests only */ + + /* true = Upgrade header was present and the parser has exited because of that. + * false = No upgrade header present. + * Should be checked when http_parser_execute() returns in addition to + * error checking. + */ + public boolean upgrade; + + /** PUBLIC **/ + // TODO : this is used in c to maintain application state. + // is this even necessary? we have state in java ? + // consider + // Object data; /* A pointer to get hook to the "connection" or "socket" object */ + + + /* + * technically we could combine all of these (except for url_mark) into one + * variable, saving stack space, but it seems more clear to have them + * separated. + */ + int header_field_mark = -1; + int header_value_mark = -1; + int url_mark = -1; + int body_mark = -1; + + /** + * Construct a Parser for ParserType.HTTP_BOTH, meaning it + * determines whether it's parsing a request or a response. + */ + public HTTPParser() { + this(ParserType.HTTP_BOTH); + } + + /** + * Construct a Parser and initialise it to parse either + * requests or responses. + */ + public HTTPParser(ParserType type) { + this.type = type; + switch(type) { + case HTTP_REQUEST: + this.state = State.start_req; + break; + case HTTP_RESPONSE: + this.state = State.start_res; + break; + case HTTP_BOTH: + this.state = State.start_req_or_res; + break; + default: + throw new HTTPException("can't happen, invalid ParserType enum"); + } + } + + /* + * Utility to facilitate System.out.println style debugging (the way god intended) + */ + static void p(Object o) {System.out.println(o);} + + /** Comment from C version follows + * + * Our URL parser. + * + * This is designed to be shared by http_parser_execute() for URL validation, + * hence it has a state transition + byte-for-byte interface. In addition, it + * is meant to be embedded in http_parser_parse_url(), which does the dirty + * work of turning state transitions URL components for its API. + * + * This function should only be invoked with non-space characters. It is + * assumed that the caller cares about (and can detect) the transition between + * URL and non-URL states by looking for these. + */ + public State parse_url_char(byte ch) { + + int chi = ch & 0xff; // utility, ch without signedness for table lookups. + + if(SPACE == ch){ + throw new HTTPException("space as url char"); + } + + switch(state) { + case req_spaces_before_url: + /* Proxied requests are followed by scheme of an absolute URI (alpha). + * All methods except CONNECT are followed by '/' or '*'. + */ + if(SLASH == ch || STAR == ch){ + return req_path; + } + if(isAtoZ(ch)){ + return req_schema; + } + break; + case req_schema: + if(isAtoZ(ch)){ + return req_schema; + } + if(COLON == ch){ + return req_schema_slash; + } + break; + case req_schema_slash: + if(SLASH == ch){ + return req_schema_slash_slash; + } + break; + case req_schema_slash_slash: + if(SLASH == ch){ + return req_host_start; + } + break; + case req_host_start: + if (ch == (byte)'[') { + return req_host_v6_start; + } + if (isHostChar(ch)) { + return req_host; + } + break; + + case req_host: + if (isHostChar(ch)) { + return req_host; + } + + /* FALLTHROUGH */ + case req_host_v6_end: + switch (ch) { + case ':': + return req_port_start; + case '/': + return req_path; + case '?': + return req_query_string_start; + } + break; + + case req_host_v6: + if (ch == ']') { + return req_host_v6_end; + } + + /* FALLTHROUGH */ + case req_host_v6_start: + if (isHex(ch) || ch == ':') { + return req_host_v6; + } + break; + + case req_port: + switch (ch) { + case '/': + return req_path; + case '?': + return req_query_string_start; + } + + /* FALLTHROUGH */ + case req_port_start: + if (isDigit(ch)) { + return req_port; + } + break; + + case req_path: + if (isNormalUrlChar(chi)) { + return req_path; + } + switch (ch) { + case '?': + return req_query_string_start; + case '#': + return req_fragment_start; + } + + break; + + case req_query_string_start: + case req_query_string: + if (isNormalUrlChar(chi)) { + return req_query_string; + } + + switch (ch) { + case '?': + /* allow extra '?' in query string */ + return req_query_string; + + case '#': + return req_fragment_start; + } + + break; + + case req_fragment_start: + if (isNormalUrlChar(chi)) { + return req_fragment; + } + switch (ch) { + case '?': + return req_fragment; + + case '#': + return req_fragment_start; + } + break; + + case req_fragment: + if (isNormalUrlChar(ch)) { + return req_fragment; + } + + switch (ch) { + case '?': + case '#': + return req_fragment; + } + + break; + default: + break; + } + + /* We should never fall out of the switch above unless there's an error */ + return dead; + } + + /** Execute the parser with the currently available data contained in + * the buffer. The buffers position() and limit() need to be set + * correctly (obviously) and a will be updated approriately when the + * method returns to reflect the consumed data. + */ + public int execute(ParserSettings settings, ByteBuffer data) { + + int p = data.position(); + this.p_start = p; // this is used for pretty printing errors. + // and returning the amount of processed bytes. + + + // In case the headers don't provide information about the content + // length, `execute` needs to be called with an empty buffer to + // indicate that all the data has been send be the client/server, + // else there is no way of knowing the message is complete. + int len = (data.limit() - data.position()); + if (0 == len) { +// if (State.body_identity_eof == state) { +// settings.call_on_message_complete(this); +// } + switch (state) { + case body_identity_eof: + settings.call_on_message_complete(this); + return data.position() - this.p_start; + + case dead: + case start_req_or_res: + case start_res: + case start_req: + return data.position() - this.p_start; + + default: + // should we really consider this an error!? + throw new HTTPException("empty bytes! "+state); // error + } + } + + + // in case the _previous_ call to the parser only has data to get to + // the middle of certain fields, we need to update marks to point at + // the beginning of the current buffer. + switch (state) { + case header_field: + header_field_mark = p; + break; + case header_value: + header_value_mark = p; + break; + case req_path: + case req_schema: + case req_schema_slash: + case req_schema_slash_slash: + case req_host_start: + case req_host_v6_start: + case req_host_v6: + case req_host_v6_end: + case req_host: + case req_port_start: + case req_port: + case req_query_string_start: + case req_query_string: + case req_fragment_start: + case req_fragment: + url_mark = p; + break; + } + boolean reexecute = false; + int pe = 0; + byte ch = 0; + int chi = 0; + byte c = -1; + int to_read = 0; + + // this is where the work gets done, traverse the available data... + while (data.position() != data.limit() || reexecute) { +// p(state + ": r: " + reexecute + " :: " +p ); + + if(!reexecute){ + p = data.position(); + pe = data.limit(); + ch = data.get(); // the current character to process. + chi = ch & 0xff; // utility, ch without signedness for table lookups. + c = -1; // utility variably used for up- and downcasing etc. + to_read = 0; // used to keep track of how much of body, etc. is left to read + + if (parsing_header(state)) { + ++nread; + if (nread > HTTP_MAX_HEADER_SIZE) { + return error(settings, "possible buffer overflow", data); + } + } + } + reexecute = false; +// p(state + " ::: " + ch + " : " + (((CR == ch) || (LF == ch)) ? ch : ("'" + (char)ch + "'")) +": "+p ); + + switch (state) { + /* + * this state is used after a 'Connection: close' message + * the parser will error out if it reads another message + */ + case dead: + if (CR == ch || LF == ch){ + break; + } + return error(settings, "Connection already closed", data); + + + + case start_req_or_res: + if (CR == ch || LF == ch){ + break; + } + flags = 0; + content_length = -1; + + if (H == ch) { + state = State.res_or_resp_H; + } else { + type = ParserType.HTTP_REQUEST; + method = start_req_method_assign(ch); + if (null == method) { + return error(settings, "invalid method", data); + } + index = 1; + state = State.req_method; + } + settings.call_on_message_begin(this); + break; + + + + case res_or_resp_H: + if (T == ch) { + type = ParserType.HTTP_RESPONSE; + state = State.res_HT; + } else { + if (E != ch) { + return error(settings, "not E", data); + } + type = ParserType.HTTP_REQUEST; + method = HTTPMethod.HTTP_HEAD; + index = 2; + state = State.req_method; + } + break; + + + + case start_res: + flags = 0; + content_length = -1; + + switch(ch) { + case H: + state = State.res_H; + break; + case CR: + case LF: + break; + default: + return error(settings, "Not H or CR/LF", data); + } + + settings.call_on_message_begin(this); + break; + + + + case res_H: + if (strict && T != ch) { + return error(settings, "Not T", data); + } + state = State.res_HT; + break; + case res_HT: + if (strict && T != ch) { +return error(settings, "Not T2", data); + } + state = State.res_HTT; + break; + case res_HTT: + if (strict && P != ch) { +return error(settings, "Not P", data); + } + state = State.res_HTTP; + break; + case res_HTTP: + if (strict && SLASH != ch) { +return error(settings, "Not '/'", data); + } + state = State.res_first_http_major; + break; + + + + case res_first_http_major: + if (!isDigit(ch)) { +return error(settings, "Not a digit", data); + } + http_major = (int) ch - 0x30; + state = State.res_http_major; + break; + + /* major HTTP version or dot */ + case res_http_major: + if (DOT == ch) { + state = State.res_first_http_minor; + break; + } + if (!isDigit(ch)) { +return error(settings, "Not a digit", data); + } + http_major *= 10; + http_major += (ch - 0x30); + + if (http_major > 999) { +return error(settings, "invalid http major version: ", data); + } + break; + + /* first digit of minor HTTP version */ + case res_first_http_minor: + if (!isDigit(ch)) { +return error(settings, "Not a digit", data); + } + http_minor = (int)ch - 0x30; + state = State.res_http_minor; + break; + + /* minor HTTP version or end of request line */ + case res_http_minor: + if (SPACE == ch) { + state = State.res_first_status_code; + break; + } + if (!isDigit(ch)) { +return error(settings, "Not a digit", data); + } + http_minor *= 10; + http_minor += (ch - 0x30); + if (http_minor > 999) { +return error(settings, "invalid http minor version: ", data); + } + break; + + + + case res_first_status_code: + if (!isDigit(ch)) { + if (SPACE == ch) { + break; + } +return error(settings, "Not a digit (status code)", data); + } + status_code = (int)ch - 0x30; + state = State.res_status_code; + break; + + case res_status_code: + if (!isDigit(ch)) { + switch(ch) { + case SPACE: + state = State.res_status; + break; + case CR: + state = State.res_line_almost_done; + break; + case LF: + state = State.header_field_start; + break; + default: +return error(settings, "not a valid status code", data); + } + break; + } + status_code *= 10; + status_code += (int)ch - 0x30; + if (status_code > 999) { +return error(settings, "ridiculous status code:", data); + } + + if (status_code > 99) { + settings.call_on_status_complete(this); + } + break; + + case res_status: + /* the human readable status. e.g. "NOT FOUND" + * we are not humans so just ignore this + * we are not men, we are devo. */ + + if (CR == ch) { + state = State.res_line_almost_done; + break; + } + if (LF == ch) { + state = State.header_field_start; + break; + } + break; + + case res_line_almost_done: + if (strict && LF != ch) { +return error(settings, "not LF", data); + } + state = State.header_field_start; + break; + + + + case start_req: + if (CR==ch || LF == ch) { + break; + } + flags = 0; + content_length = -1; + + if(!isAtoZ(ch)){ + return error(settings, "invalid method", data); + } + + method = start_req_method_assign(ch); + if (null == method) { + return error(settings, "invalid method", data); + } + index = 1; + state = State.req_method; + + settings.call_on_message_begin(this); + break; + + + + case req_method: + if (0 == ch) { + return error(settings, "NULL in method", data); + } + + byte [] arr = method.bytes; + + if (SPACE == ch && index == arr.length) { + state = State.req_spaces_before_url; + } else if (arr[index] == ch) { + // wuhu! + } else if (HTTPMethod.HTTP_CONNECT == method) { + if (1 == index && H == ch) { + method = HTTPMethod.HTTP_CHECKOUT; + } else if (2 == index && P == ch) { + method = HTTPMethod.HTTP_COPY; + } + } else if (HTTPMethod.HTTP_MKCOL == method) { + if (1 == index && O == ch) { + method = HTTPMethod.HTTP_MOVE; + } else if (1 == index && E == ch) { + method = HTTPMethod.HTTP_MERGE; + } else if (1 == index && DASH == ch) { /* M-SEARCH */ + method = HTTPMethod.HTTP_MSEARCH; + } else if (2 == index && A == ch) { + method = HTTPMethod.HTTP_MKACTIVITY; + } + } else if (1 == index && HTTPMethod.HTTP_POST == method) { + if(R == ch) { + method = HTTPMethod.HTTP_PROPFIND; /* or HTTP_PROPPATCH */ + }else if(U == ch){ + method = HTTPMethod.HTTP_PUT; /* or HTTP_PURGE */ + }else if(A == ch){ + method = HTTPMethod.HTTP_PATCH; + } + } else if (2 == index) { + if(HTTPMethod.HTTP_PUT == method) { + if(R == ch){ + method = HTTPMethod.HTTP_PURGE; + } + }else if(HTTPMethod.HTTP_UNLOCK == method){ + if(S == ch){ + method = HTTPMethod.HTTP_UNSUBSCRIBE; + } + } + }else if(4 == index && HTTPMethod.HTTP_PROPFIND == method && P == ch){ + method = HTTPMethod.HTTP_PROPPATCH; + } else { + return error(settings, "Invalid HTTP method", data); + } + + ++index; + break; + + + + /******************* URL *******************/ + case req_spaces_before_url: + if (SPACE == ch) { + break; + } + url_mark = p; + if(HTTPMethod.HTTP_CONNECT == method){ + state = req_host_start; + } + + state = parse_url_char(ch); + if(state == dead){ + return error(settings, "Invalid something", data); + } + break; + + + case req_schema: + case req_schema_slash: + case req_schema_slash_slash: + case req_host_start: + case req_host_v6_start: + case req_host_v6: + case req_port_start: + switch (ch) { + /* No whitespace allowed here */ + case SPACE: + case CR: + case LF: + return error(settings, "unexpected char in path", data); + default: + state = parse_url_char(ch); + if(dead == state){ + return error(settings, "unexpected char in path", data); + } + } + break; + + case req_host: + case req_host_v6_end: + case req_port: + case req_path: + case req_query_string_start: + case req_query_string: + case req_fragment_start: + case req_fragment: + switch (ch) { + case SPACE: + settings.call_on_url(this, data, url_mark, p-url_mark); + settings.call_on_path(this, data, url_mark, p - url_mark); + url_mark = -1; + state = State.req_http_start; + break; + case CR: + case LF: + http_major = 0; + http_minor = 9; + state = (CR == ch) ? req_line_almost_done : header_field_start; + settings.call_on_url(this, data, url_mark, p-url_mark); //TODO check params!!! + settings.call_on_path(this, data, url_mark, p-url_mark); + url_mark = -1; + break; + default: + state = parse_url_char(ch); + if(dead == state){ + return error(settings, "unexpected char in path", data); + } + } + break; + /******************* URL *******************/ + + + + /******************* HTTP 1.1 *******************/ + case req_http_start: + switch (ch) { + case H: + state = State.req_http_H; + break; + case SPACE: + break; + default: + return error(settings, "error in req_http_H", data); + } + break; + + case req_http_H: + if (strict && T != ch) { + return error(settings, "unexpected char", data); + } + state = State.req_http_HT; + break; + + case req_http_HT: + if (strict && T != ch) { + return error(settings, "unexpected char", data); + } + state = State.req_http_HTT; + break; + + case req_http_HTT: + if (strict && P != ch) { + return error(settings, "unexpected char", data); + } + state = State.req_http_HTTP; + break; + + case req_http_HTTP: + if (strict && SLASH != ch) { + return error(settings, "unexpected char", data); + } + state = req_first_http_major; + break; + + /* first digit of major HTTP version */ + case req_first_http_major: + if (!isDigit(ch)) { +return error(settings, "non digit in http major", data); + } + http_major = (int)ch - 0x30; + state = State.req_http_major; + break; + + /* major HTTP version or dot */ + case req_http_major: + if (DOT == ch) { + state = State.req_first_http_minor; + break; + } + + if (!isDigit(ch)) { +return error(settings, "non digit in http major", data); + } + + http_major *= 10; + http_major += (int)ch - 0x30; + + if (http_major > 999) { +return error(settings, "ridiculous http major", data); + }; + break; + + /* first digit of minor HTTP version */ + case req_first_http_minor: + if (!isDigit(ch)) { +return error(settings, "non digit in http minor", data); + } + http_minor = (int)ch - 0x30; + state = State.req_http_minor; + break; + + case req_http_minor: + if (ch == CR) { + state = State.req_line_almost_done; + break; + } + + if (ch == LF) { + state = State.header_field_start; + break; + } + + /* XXX allow spaces after digit? */ + + if (!isDigit(ch)) { +return error(settings, "non digit in http minor", data); + } + + http_minor *= 10; + http_minor += (int)ch - 0x30; + + + if (http_minor > 999) { +return error(settings, "ridiculous http minor", data); + }; + + break; + + /* end of request line */ + case req_line_almost_done: + { + if (ch != LF) { +return error(settings, "missing LF after request line", data); + } + state = header_field_start; + break; + } + + /******************* HTTP 1.1 *******************/ + + + + /******************* Header *******************/ + case header_field_start: + { + if (ch == CR) { + state = headers_almost_done; + break; + } + + if (ch == LF) { + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + state = State.headers_almost_done; + reexecute = true; + break; + } + + c = token(ch); + + if (0 == c) { + return error(settings, "invalid char in header:", data); + } + + header_field_mark = p; + + index = 0; + state = State.header_field; + + switch (c) { + case C: + header_state = HState.C; + break; + + case P: + header_state = HState.matching_proxy_connection; + break; + + case T: + header_state = HState.matching_transfer_encoding; + break; + + case U: + header_state = HState.matching_upgrade; + break; + + default: + header_state = HState.general; + break; + } + break; + } + + + + case header_field: + { + c = token(ch); + if (0 != c) { + switch (header_state) { + case general: + break; + + case C: + index++; + header_state = (O == c ? HState.CO : HState.general); + break; + + case CO: + index++; + header_state = (N == c ? HState.CON : HState.general); + break; + + case CON: + index++; + switch (c) { + case N: + header_state = HState.matching_connection; + break; + case T: + header_state = HState.matching_content_length; + break; + default: + header_state = HState.general; + break; + } + break; + + /* connection */ + + case matching_connection: + index++; + if (index > CONNECTION.length || c != CONNECTION[index]) { + header_state = HState.general; + } else if (index == CONNECTION.length-1) { + header_state = HState.connection; + } + break; + + /* proxy-connection */ + + case matching_proxy_connection: + index++; + if (index > PROXY_CONNECTION.length || c != PROXY_CONNECTION[index]) { + header_state = HState.general; + } else if (index == PROXY_CONNECTION.length-1) { + header_state = HState.connection; + } + break; + + /* content-length */ + + case matching_content_length: + index++; + if (index > CONTENT_LENGTH.length || c != CONTENT_LENGTH[index]) { + header_state = HState.general; + } else if (index == CONTENT_LENGTH.length-1) { + header_state = HState.content_length; + } + break; + + /* transfer-encoding */ + + case matching_transfer_encoding: + index++; + if (index > TRANSFER_ENCODING.length || c != TRANSFER_ENCODING[index]) { + header_state = HState.general; + } else if (index == TRANSFER_ENCODING.length-1) { + header_state = HState.transfer_encoding; + } + break; + + /* upgrade */ + + case matching_upgrade: + index++; + if (index > UPGRADE.length || c != UPGRADE[index]) { + header_state = HState.general; + } else if (index == UPGRADE.length-1) { + header_state = HState.upgrade; + } + break; + + case connection: + case content_length: + case transfer_encoding: + case upgrade: + if (SPACE != ch) header_state = HState.general; + break; + + default: +return error(settings, "Unknown Header State", data); + } // switch: header_state + break; + } // 0 != c + + if (COLON == ch) { + settings.call_on_header_field(this, data, header_field_mark, p-header_field_mark); + header_field_mark = -1; + + state = State.header_value_start; + break; + } + + if (CR == ch) { + state = State.header_almost_done; + settings.call_on_header_field(this, data, header_field_mark, p-header_field_mark); + + header_field_mark = -1; + break; + } + + if (ch == LF) { + settings.call_on_header_field(this, data, header_field_mark, p-header_field_mark); + header_field_mark = -1; + + state = State.header_field_start; + break; + } + +return error(settings, "invalid header field", data); + } + + + + case header_value_start: + { + if ((SPACE == ch) || (TAB == ch)) break; + + header_value_mark = p; + + state = State.header_value; + index = 0; + + + if (CR == ch) { + settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark); + header_value_mark = -1; + + header_state = HState.general; + state = State.header_almost_done; + break; + } + + if (LF == ch) { + settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark); + header_value_mark = -1; + + state = State.header_field_start; + break; + } + + + c = upper(ch); + + switch (header_state) { + case upgrade: + flags |= F_UPGRADE; + header_state = HState.general; + break; + + case transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if (C == c) { + header_state = HState.matching_transfer_encoding_chunked; + } else { + header_state = HState.general; + } + break; + + case content_length: + if (!isDigit(ch)) { +return error(settings, "Content-Length not numeric", data); + } + content_length = (int)ch - 0x30; + break; + + case connection: + /* looking for 'Connection: keep-alive' */ + if (K == c) { + header_state = HState.matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (C == c) { + header_state = HState.matching_connection_close; + } else { + header_state = HState.general; + } + break; + + default: + header_state = HState.general; + break; + } + break; + } // header value start + + + + case header_value: + { + + if (CR == ch) { + settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark); + header_value_mark = -1; + + state = State.header_almost_done; + break; + } + + if (LF == ch) { + settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark); + header_value_mark = -1; + state = header_almost_done; + reexecute = true; + break; + } + + c = upper(ch); + switch (header_state) { + case general: + break; + + case connection: + case transfer_encoding: +return error(settings, "Shouldn't be here", data); + + case content_length: + if (SPACE == ch) { + break; + } + if (!isDigit(ch)) { +return error(settings, "Content-Length not numeric", data); + } + + long t = content_length; + t *= 10; + t += (long)ch - 0x30; + + /* Overflow? */ + // t will wrap and become negative ... + if (t < content_length) { + return error(settings, "Invalid content length", data); + } + content_length = t; + break; + + /* Transfer-Encoding: chunked */ + case matching_transfer_encoding_chunked: + index++; + if (index > CHUNKED.length || c != CHUNKED[index]) { + header_state = HState.general; + } else if (index == CHUNKED.length-1) { + header_state = HState.transfer_encoding_chunked; + } + break; + + /* looking for 'Connection: keep-alive' */ + case matching_connection_keep_alive: + index++; + if (index > KEEP_ALIVE.length || c != KEEP_ALIVE[index]) { + header_state = HState.general; + } else if (index == KEEP_ALIVE.length-1) { + header_state = HState.connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case matching_connection_close: + index++; + if (index > CLOSE.length || c != CLOSE[index]) { + header_state = HState.general; + } else if (index == CLOSE.length-1) { + header_state = HState.connection_close; + } + break; + + case transfer_encoding_chunked: + case connection_keep_alive: + case connection_close: + if (SPACE != ch) header_state = HState.general; + break; + + default: + state = State.header_value; + header_state = HState.general; + break; + } + break; + } // header_value + + + + case header_almost_done: + if (!header_almost_done(ch)) { + return error(settings, "incorrect header ending, expecting LF", data); + } + break; + + case header_value_lws: + if (SPACE == ch || TAB == ch ){ + state = header_value_start; + } else { + state = header_field_start; + reexecute = true; + } + break; + + case headers_almost_done: + if (LF != ch) { + return error(settings, "header not properly completed", data); + } + if (0 != (flags & F_TRAILING)) { + /* End of a chunked request */ + state = new_message(); + settings.call_on_headers_complete(this); + settings.call_on_message_complete(this); + break; + } + + state = headers_done; + + if (0 != (flags & F_UPGRADE) || HTTPMethod.HTTP_CONNECT == method) { + upgrade = true; + } + + /* Here we call the headers_complete callback. This is somewhat + * different than other callbacks because if the user returns 1, we + * will interpret that as saying that this message has no body. This + * is needed for the annoying case of recieving a response to a HEAD + * request. + */ + + /* (responses to HEAD request contain a CONTENT-LENGTH header + * but no content) + * + * Consider what to do here: I don't like the idea of the callback + * interface having a different contract in the case of HEAD + * responses. The alternatives would be either to: + * + * a.) require the header_complete callback to implement a different + * interface or + * + * b.) provide an overridden execute(bla, bla, boolean + * parsingHeader) implementation ... + */ + + /*TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO */ + if (null != settings.on_headers_complete) { + settings.call_on_headers_complete(this); + //return; + } + + // if (null != settings.on_headers_complete) { + // switch (settings.on_headers_complete.cb(parser)) { + // case 0: + // break; + // + // case 1: + // flags |= F_SKIPBODY; + // break; + // + // default: + // return p - data; /* Error */ // TODO // RuntimeException ? + // } + // } + reexecute = true; + break; + + case headers_done: + if (strict && (LF != ch)) { + return error(settings, "STRICT CHECK", data); //TODO correct error msg + } + + nread = 0; + + // Exit, the rest of the connect is in a different protocol. + if (upgrade) { + state = new_message(); + settings.call_on_message_complete(this); + return data.position()-this.p_start; + } + + if (0 != (flags & F_SKIPBODY)) { + state = new_message(); + settings.call_on_message_complete(this); + } else if (0 != (flags & F_CHUNKED)) { + /* chunked encoding - ignore Content-Length header */ + state = State.chunk_size_start; + } else { + if (content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + state = new_message(); + settings.call_on_message_complete(this); + } else if (content_length != -1) { + /* Content-Length header given and non-zero */ + state = State.body_identity; + } else { + if (type == ParserType.HTTP_REQUEST || !http_message_needs_eof()) { + /* Assume content-length 0 - read the next */ + state = new_message(); + settings.call_on_message_complete(this); + } else { + /* Read body until EOF */ + state = State.body_identity_eof; + } + } + } + + break; + /******************* Header *******************/ + + + + + /******************* Body *******************/ + case body_identity: + to_read = min(pe - p, content_length); //TODO change to use buffer? + body_mark = p; + + if (to_read > 0) { + settings.call_on_body(this, data, p, to_read); + data.position(p+to_read); + content_length -= to_read; + + if (content_length == 0) { + state = message_done; + reexecute = true; + } + } + break; + + + + case body_identity_eof: + to_read = pe - p; // TODO change to use buffer ? + if (to_read > 0) { + settings.call_on_body(this, data, p, to_read); + data.position(p+to_read); + } + break; + + case message_done: + state = new_message(); + settings.call_on_message_complete(this); + break; + /******************* Body *******************/ + + + + /******************* Chunk *******************/ + case chunk_size_start: + if (1 != this.nread) { +return error(settings, "nread != 1 (chunking)", data); + + } + if (0 == (flags & F_CHUNKED)) { +return error(settings, "not chunked", data); + } + + c = UNHEX[chi]; + if (c == -1) { +return error(settings, "invalid hex char in chunk content length", data); + } + content_length = c; + state = State.chunk_size; + break; + + + + case chunk_size: + if (0 == (flags & F_CHUNKED)) { + return error(settings, "not chunked", data); + } + + if (CR == ch) { + state = State.chunk_size_almost_done; + break; + } + + c = UNHEX[chi]; + + if (c == -1) { + if (SEMI == ch || SPACE == ch) { + state = State.chunk_parameters; + break; + } + return error(settings, "invalid hex char in chunk content length", data); + } + long t = content_length; + + t *= 16; + t += c; + if(t < content_length){ + return error(settings, "invalid content length", data); + } + content_length = t; + break; + + + + case chunk_parameters: + if (0 == (flags & F_CHUNKED)) { +return error(settings, "not chunked", data); + } + /* just ignore this shit. TODO check for overflow */ + if (CR == ch) { + state = State.chunk_size_almost_done; + break; + } + break; + + + + case chunk_size_almost_done: + if (0 == (flags & F_CHUNKED)) { +return error(settings, "not chunked", data); + } + if (strict && LF != ch) { +return error(settings, "expected LF at end of chunk size", data); + } + + this.nread = 0; + + if (0 == content_length) { + flags |= F_TRAILING; + state = State.header_field_start; + } else { + state = State.chunk_data; + } + break; + + + + case chunk_data: + //TODO Apply changes from C version for s_chunk_data + if (0 == (flags & F_CHUNKED)) { + return error(settings, "not chunked", data); + } + + to_read = min(pe-p, content_length); + if (to_read > 0) { + settings.call_on_body(this, data, p, to_read); + data.position(p+to_read); + } + + if (to_read == content_length) { + state = State.chunk_data_almost_done; + } + + content_length -= to_read; + break; + + + + case chunk_data_almost_done: + if (0 == (flags & F_CHUNKED)) { +return error(settings, "not chunked", data); + } + if (strict && CR != ch) { +return error(settings, "chunk data terminated incorrectly, expected CR", data); + } + state = State.chunk_data_done; + //TODO CALLBACK_DATA(body) + // settings.call_on_body(this, data,p,?); + break; + + + + case chunk_data_done: + if (0 == (flags & F_CHUNKED)) { +return error(settings, "not chunked", data); + } + if (strict && LF != ch) { +return error(settings, "chunk data terminated incorrectly, expected LF", data); + } + state = State.chunk_size_start; + break; + /******************* Chunk *******************/ + + + + default: +return error(settings, "unhandled state", data); + + } // switch + } // while + + p = data.position(); + + + /* Reaching this point assumes that we only received part of a + * message, inform the callbacks about the progress made so far*/ + + settings.call_on_header_field(this, data, header_field_mark, p-header_field_mark); + settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark); + settings.call_on_url (this, data, url_mark, p-url_mark); + settings.call_on_path (this, data, url_mark, p-url_mark); + + return data.position()-this.p_start; + } // execute + + int error (ParserSettings settings, String mes, ByteBuffer data) { + settings.call_on_error(this, mes, data, this.p_start); + this.state = State.dead; + return data.position()-this.p_start; + } + + public boolean http_message_needs_eof() { + if(type == ParserType.HTTP_REQUEST){ + return false; + } + /* See RFC 2616 section 4.4 */ + if ((status_code / 100 == 1) || /* 1xx e.g. Continue */ + (status_code == 204) || /* No Content */ + (status_code == 304) || /* Not Modified */ + (flags & F_SKIPBODY) != 0) { /* response to a HEAD request */ + return false; + } + if ((flags & F_CHUNKED) != 0 || content_length != -1) { + return false; + } + + return true; + } + + /* If http_should_keep_alive() in the on_headers_complete or + * on_message_complete callback returns true, then this will be should be + * the last message on the connection. + * If you are the server, respond with the "Connection: close" header. + * If you are the client, close the connection. + */ + public boolean http_should_keep_alive() { + if (http_major > 0 && http_minor > 0) { + /* HTTP/1.1 */ + if ( 0 != (flags & F_CONNECTION_CLOSE) ) { + return false; + } + } else { + /* HTTP/1.0 or earlier */ + if ( 0 == (flags & F_CONNECTION_KEEP_ALIVE) ) { + return false; + } + } + return !http_message_needs_eof(); + } + + public int parse_url(ByteBuffer data, boolean is_connect, HTTPParserUrl u) { + + UrlFields uf = UrlFields.UF_MAX; + UrlFields old_uf = UrlFields.UF_MAX; + u.port = 0; + u.field_set = 0; + state = (is_connect ? State.req_host_start : State.req_spaces_before_url); + int p_init = data.position(); + int p = 0; + byte ch = 0; + while (data.position() != data.limit()) { + p = data.position(); + ch = data.get(); + state = parse_url_char(ch); + switch(state) { + case dead: + return 1; + + /* Skip delimeters */ + case req_schema_slash: + case req_schema_slash_slash: + case req_host_start: + case req_host_v6_start: + case req_host_v6_end: + case req_port_start: + case req_query_string_start: + case req_fragment_start: + continue; + + case req_schema: + uf = UrlFields.UF_SCHEMA; + break; + + case req_host: + case req_host_v6: + uf = UrlFields.UF_HOST; + break; + + case req_port: + uf = UrlFields.UF_PORT; + break; + + case req_path: + uf = UrlFields.UF_PATH; + break; + + case req_query_string: + uf = UrlFields.UF_QUERY; + break; + + case req_fragment: + uf = UrlFields.UF_FRAGMENT; + break; + + default: + return 1; + } + /* Nothing's changed; soldier on */ + if (uf == old_uf) { + u.field_data[uf.getIndex()].len++; + continue; + } + + u.field_data[uf.getIndex()].off = p - p_init; + u.field_data[uf.getIndex()].len = 1; + + u.field_set |= (1 << uf.getIndex()); + old_uf = uf; + + } + + /* CONNECT requests can only contain "hostname:port" */ + if (is_connect && u.field_set != ((1 << UrlFields.UF_HOST.getIndex())|(1 << UrlFields.UF_PORT.getIndex()))) { + return 1; + } + + /* Make sure we don't end somewhere unexpected */ + switch (state) { + case req_host_v6_start: + case req_host_v6: + case req_host_v6_end: + case req_host: + case req_port_start: + return 1; + default: + break; + } + + if (0 != (u.field_set & (1 << UrlFields.UF_PORT.getIndex()))) { + /* Don't bother with endp; we've already validated the string */ + int v = strtoi(data, p_init + u.field_data[UrlFields.UF_PORT.getIndex()].off); + + /* Ports have a max value of 2^16 */ + if (v > 0xffff) { + return 1; + } + + u.port = v; + } + + return 0; + } + + //hacky reimplementation of srttoul, tailored for our simple needs + //we only need to parse port val, so no negative values etc + int strtoi(ByteBuffer data, int start_pos) { + data.position(start_pos); + byte ch; + String str = ""; + while(data.position() < data.limit()) { + ch = data.get(); + if(Character.isWhitespace((char)ch)){ + continue; + } + if(isDigit(ch)){ + str = str + (char)ch; //TODO replace with something less hacky + }else{ + break; + } + } + return Integer.parseInt(str); + } + + boolean isDigit(byte b) { + if (b >= 0x30 && b <=0x39) { + return true; + } + return false; + } + + boolean isHex(byte b) { + return isDigit(b) || (lower(b) >= 0x61 /*a*/ && lower(b) <= 0x66 /*f*/); + } + + boolean isAtoZ(byte b) { + byte c = lower(b); + return (c>= 0x61 /*a*/ && c <= 0x7a /*z*/); + } + + + byte lower (byte b) { + return (byte)(b|0x20); + } + + byte upper(byte b) { + char c = (char)(b); + return (byte)Character.toUpperCase(c); + } + + byte token(byte b) { + if(!strict){ + return (b == (byte)' ') ? (byte)' ' : (byte)tokens[b] ; + }else{ + return (byte)tokens[b]; + } + } + + boolean isHostChar(byte ch){ + if(!strict){ + return (isAtoZ(ch)) || isDigit(ch) || DOT == ch || DASH == ch || UNDER == ch ; + }else{ + return (isAtoZ(ch)) || isDigit(ch) || DOT == ch || DASH == ch; + } + } + + boolean isNormalUrlChar(int chi) { + if(!strict){ + return (chi > 0x80) || normal_url_char[chi]; + }else{ + return normal_url_char[chi]; + } + } + + HTTPMethod start_req_method_assign(byte c){ + switch (c) { + case C: return HTTPMethod.HTTP_CONNECT; /* or COPY, CHECKOUT */ + case D: return HTTPMethod.HTTP_DELETE; + case G: return HTTPMethod.HTTP_GET; + case H: return HTTPMethod.HTTP_HEAD; + case L: return HTTPMethod.HTTP_LOCK; + case M: return HTTPMethod.HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ + case N: return HTTPMethod.HTTP_NOTIFY; + case O: return HTTPMethod.HTTP_OPTIONS; + case P: return HTTPMethod.HTTP_POST; /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ + case R: return HTTPMethod.HTTP_REPORT; + case S: return HTTPMethod.HTTP_SUBSCRIBE; + case T: return HTTPMethod.HTTP_TRACE; + case U: return HTTPMethod.HTTP_UNLOCK; /* or UNSUBSCRIBE */ + } + return null; // ugh. + } + + boolean header_almost_done(byte ch) { + if (strict && LF != ch) { + return false; + } + + state = State.header_value_lws; + // TODO java enums support some sort of bitflag mechanism !? + switch (header_state) { + case connection_keep_alive: + flags |= F_CONNECTION_KEEP_ALIVE; + break; + case connection_close: + flags |= F_CONNECTION_CLOSE; + break; + case transfer_encoding_chunked: + flags |= F_CHUNKED; + break; + default: + break; + } + return true; + } + +// boolean headers_almost_done (byte ch, ParserSettings settings) { +// } // headers_almost_done + + + final int min (int a, int b) { + return a < b ? a : b; + } + + final int min (int a, long b) { + return a < b ? a : (int)b; + } + + /* probably not the best place to hide this ... */ + public boolean HTTP_PARSER_STRICT; + State new_message() { + if (HTTP_PARSER_STRICT){ + return http_should_keep_alive() ? start_state() : State.dead; + } else { + return start_state(); + } + + } + + State start_state() { + return type == ParserType.HTTP_REQUEST ? State.start_req : State.start_res; + } + + + boolean parsing_header(State state) { + + switch (state) { + case chunk_data : + case chunk_data_almost_done : + case chunk_data_done : + case body_identity : + case body_identity_eof : + case message_done : + return false; + + } + return true; + } + + /* "Dial C for Constants" */ + static class C { + static final int HTTP_MAX_HEADER_SIZE = 80 * 1024; + + static final int F_CHUNKED = 1 << 0; + static final int F_CONNECTION_KEEP_ALIVE = 1 << 1; + static final int F_CONNECTION_CLOSE = 1 << 2; + static final int F_TRAILING = 1 << 3; + static final int F_UPGRADE = 1 << 4; + static final int F_SKIPBODY = 1 << 5; + + static final byte [] UPCASE = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x38,0x39,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x41,0x42,0x43,0x44,0x45,0x46,0x47, 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, 0x58,0x59,0x5a,0x00,0x00,0x00,0x00,0x5f, + 0x00,0x41,0x42,0x43,0x44,0x45,0x46,0x47, 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, 0x58,0x59,0x5a,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }; + static final byte [] CONNECTION = { + 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, + }; + static final byte [] PROXY_CONNECTION = { + 0x50, 0x52, 0x4f, 0x58, 0x59, 0x2d, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, + }; + static final byte [] CONTENT_LENGTH = { + 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x2d, 0x4c, 0x45, 0x4e, 0x47, 0x54, 0x48, + }; + static final byte [] TRANSFER_ENCODING = { + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x2d, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, + }; + static final byte [] UPGRADE = { + 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x45, + }; + static final byte [] CHUNKED = { + 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x45, 0x44, + }; + static final byte [] KEEP_ALIVE = { + 0x4b, 0x45, 0x45, 0x50, 0x2d, 0x41, 0x4c, 0x49, 0x56, 0x45, + }; + static final byte [] CLOSE = { + 0x43, 0x4c, 0x4f, 0x53, 0x45, + }; + + /* Tokens as defined by rfc 2616. Also lowercases them. + * token = 1* + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + */ + + static final char [] tokens = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0, '!', 0, '#', '$', '%', '&', '\'', +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 0, 0, '*', '+', 0, '-', '.', 0 , +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + '0', '1', '2', '3', '4', '5', '6', '7', +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + '8', '9', 0, 0, 0, 0, 0, 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 'X', 'Y', 'Z', 0, 0, 0, 0, '_', +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 'X', 'Y', 'Z', 0, '|', 0, '~', 0, +/* hi bit set, not ascii */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }; + + static final byte [] UNHEX = + { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; + + static final boolean [] normal_url_char = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + false, false, false, false, false, false, false, false, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + false, false, false, false, false, false, false, false, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + false, false, false, false, false, false, false, false, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + false, false, false, false, false, false, false, false, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + false, true, true, false, true, true, true, true, +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + true, true, true, true, true, true, true, true, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + true, true, true, true, true, true, true, true, +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + true, true, true, true, true, true, true, false, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + true, true, true, true, true, true, true, true, +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + true, true, true, true, true, true, true, true, +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + true, true, true, true, true, true, true, true, +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + true, true, true, true, true, true, true, true, +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + true, true, true, true, true, true, true, true, +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + true, true, true, true, true, true, true, true, +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + true, true, true, true, true, true, true, true, +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + true, true, true, true, true, true, true, false, + +/* hi bit set, not ascii */ +/* Remainder of non-ASCII range are accepted as-is to support implicitly UTF-8 + * encoded paths. This is out of spec, but clients generate this and most other + * HTTP servers support it. We should, too. */ + + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + + }; + + public static final byte A = 0x41; + public static final byte B = 0x42; + public static final byte C = 0x43; + public static final byte D = 0x44; + public static final byte E = 0x45; + public static final byte F = 0x46; + public static final byte G = 0x47; + public static final byte H = 0x48; + public static final byte I = 0x49; + public static final byte J = 0x4a; + public static final byte K = 0x4b; + public static final byte L = 0x4c; + public static final byte M = 0x4d; + public static final byte N = 0x4e; + public static final byte O = 0x4f; + public static final byte P = 0x50; + public static final byte Q = 0x51; + public static final byte R = 0x52; + public static final byte S = 0x53; + public static final byte T = 0x54; + public static final byte U = 0x55; + public static final byte V = 0x56; + public static final byte W = 0x57; + public static final byte X = 0x58; + public static final byte Y = 0x59; + public static final byte Z = 0x5a; + public static final byte UNDER = 0x5f; + public static final byte CR = 0x0d; + public static final byte LF = 0x0a; + public static final byte DOT = 0x2e; + public static final byte SPACE = 0x20; + public static final byte TAB = 0x09; + public static final byte SEMI = 0x3b; + public static final byte COLON = 0x3a; + public static final byte HASH = 0x23; + public static final byte QMARK = 0x3f; + public static final byte SLASH = 0x2f; + public static final byte DASH = 0x2d; + public static final byte STAR = 0x2a; + public static final byte NULL = 0x00; + } + + enum State { + + dead + + , start_req_or_res + , res_or_resp_H + , start_res + , res_H + , res_HT + , res_HTT + , res_HTTP + , res_first_http_major + , res_http_major + , res_first_http_minor + , res_http_minor + , res_first_status_code + , res_status_code + , res_status + , res_line_almost_done + + , start_req + + , req_method + , req_spaces_before_url + , req_schema + , req_schema_slash + , req_schema_slash_slash + , req_host_start + , req_host_v6_start + , req_host_v6 + , req_host_v6_end + , req_host + , req_port_start + , req_port + , req_path + , req_query_string_start + , req_query_string + , req_fragment_start + , req_fragment + , req_http_start + , req_http_H + , req_http_HT + , req_http_HTT + , req_http_HTTP + , req_first_http_major + , req_http_major + , req_first_http_minor + , req_http_minor + , req_line_almost_done + + , header_field_start + , header_field + , header_value_start + , header_value + , header_value_lws + + , header_almost_done + + , chunk_size_start + , chunk_size + , chunk_parameters + , chunk_size_almost_done + + , headers_almost_done + , headers_done +// This space intentionally not left blank, comment from c, for orientation... +// the c version uses <= s_header_almost_done in java, we list the states explicitly +// in `parsing_header()` +/* Important: 's_headers_done' must be the last 'header' state. All + * states beyond this must be 'body' states. It is used for overflow + * checking. See the PARSING_HEADER() macro. + */ + , chunk_data + , chunk_data_almost_done + , chunk_data_done + + , body_identity + , body_identity_eof + , message_done + + } + enum HState { + general + , C + , CO + , CON + + , matching_connection + , matching_proxy_connection + , matching_content_length + , matching_transfer_encoding + , matching_upgrade + + , connection + , content_length + , transfer_encoding + , upgrade + + , matching_transfer_encoding_chunked + , matching_connection_keep_alive + , matching_connection_close + + , transfer_encoding_chunked + , connection_keep_alive + , connection_close + } + public enum UrlFields { + UF_SCHEMA(0) + , UF_HOST(1) + , UF_PORT(2) + , UF_PATH(3) + , UF_QUERY(4) + , UF_FRAGMENT(5) + , UF_MAX(6); + + + private final int index; + + private UrlFields(int index) { + this.index = index; + } + public int getIndex() { + return index; + } + + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java new file mode 100644 index 0000000..1ebdd4f --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java @@ -0,0 +1,83 @@ +package http_parser.lolevel; +import java.nio.ByteBuffer; +import http_parser.HTTPException; +public class ParserSettings { + + public HTTPCallback on_message_begin; + public HTTPDataCallback on_path; + public HTTPDataCallback on_query_string; + public HTTPDataCallback on_url; + public HTTPDataCallback on_fragment; + public HTTPCallback on_status_complete; + public HTTPDataCallback on_header_field; + public HTTPDataCallback on_header_value; + public HTTPCallback on_headers_complete; + public HTTPDataCallback on_body; + public HTTPCallback on_message_complete; + public HTTPErrorCallback on_error; + + void call_on_message_begin (HTTPParser p) { + call_on(on_message_begin, p); + } + + void call_on_message_complete (HTTPParser p) { + call_on(on_message_complete, p); + } + + // this one is a little bit different: + // the current `position` of the buffer is the location of the + // error, `ini_pos` indicates where the position of + // the buffer when it was passed to the `execute` method of the parser, i.e. + // using this information and `limit` we'll know all the valid data + // in the buffer around the error we can use to print pretty error + // messages. + void call_on_error (HTTPParser p, String mes, ByteBuffer buf, int ini_pos) { + if (null != on_error) { + on_error.cb(p, mes, buf, ini_pos); + return; + } + // if on_error gets called it MUST throw an exception, else the parser + // will attempt to continue parsing, which it can't because it's + // in an invalid state. + throw new HTTPException(mes); + } + + void call_on_header_field (HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_header_field, p, buf, pos, len); + } + void call_on_query_string (HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_query_string, p, buf, pos, len); + } + void call_on_fragment (HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_fragment, p, buf, pos, len); + } + void call_on_status_complete(HTTPParser p) { + call_on(on_status_complete, p); + } + void call_on_path (HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_path, p, buf, pos, len); + } + void call_on_header_value (HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_header_value, p, buf, pos, len); + } + void call_on_url (HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_url, p, buf, pos, len); + } + void call_on_body(HTTPParser p, ByteBuffer buf, int pos, int len) { + call_on(on_body, p, buf, pos, len); + } + void call_on_headers_complete(HTTPParser p) { + call_on(on_headers_complete, p); + } + void call_on (HTTPCallback cb, HTTPParser p) { + // cf. CALLBACK2 macro + if (null != cb) { + cb.cb(p); + } + } + void call_on (HTTPDataCallback cb, HTTPParser p, ByteBuffer buf, int pos, int len) { + if (null != cb && -1 != pos) { + cb.cb(p,buf,pos,len); + } + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java new file mode 100644 index 0000000..62f0a0e --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java @@ -0,0 +1,374 @@ +package http_parser.lolevel; + +import java.nio.*; +import java.io.*; +import java.util.*; + +import http_parser.HTTPMethod; +import http_parser.HTTPParserUrl; +import http_parser.ParserType; +import http_parser.lolevel.TestLoaderNG.Header; +import http_parser.lolevel.TestLoaderNG.LastHeader; + +import primitive.collection.ByteList; + +import static http_parser.lolevel.Util.str; + +public class Message { + String name; + byte [] raw; + ParserType type; + HTTPMethod method; + int status_code; + String request_path; // byte [] ? + String request_url; + String fragment ; + String query_string; + byte [] body; + int body_size; + int num_headers; + LastHeader last_header_element; + Map header; + List
    headers; + boolean should_keep_alive; + + byte[] upgrade; + boolean upgrade() { + return null != upgrade; + } + + int http_major; + int http_minor; + + boolean message_begin_called; + boolean headers_complete_called; + boolean message_complete_called; + boolean message_complete_on_eof; + + + Map parsed_header; + String currHField; + String currHValue; + byte [] pbody; + int num_called; + + public String toString() { + StringBuilder b = new StringBuilder(); + b.append("NAME: "); b.append(name);b.append("\n"); + b.append("type: "); b.append(type);b.append("\n"); + b.append("method: "); b.append(method);b.append("\n"); + b.append("status_code: "); b.append(status_code);b.append("\n"); + b.append("request_path: "); b.append(request_path);b.append("\n"); + b.append("request_url: "); b.append(request_url);b.append("\n"); + b.append("fragment: "); b.append(fragment);b.append("\n"); + b.append("query_string: "); b.append(query_string);b.append("\n"); + b.append("body:\n"); b.append(new String(body));b.append("\n"); + b.append("should_keep_alive: "); b.append(should_keep_alive);b.append("\n"); + b.append("upgrade: "); b.append(upgrade);b.append("\n"); + b.append("http_major: "); b.append(http_major);b.append("\n"); + b.append("http_minor: "); b.append(http_minor);b.append("\n"); + b.append("message_complete_called: "); b.append(message_complete_called);b.append("\n"); + return b.toString(); + } + + Message () { + this.header = new HashMap(); + this.headers = new LinkedList
    (); + reset(); + } + /* + *prepare this Test Instance for reuse. + * */ + void reset () { + this.parsed_header = new HashMap(); + this.pbody = null; + this.num_called = 0; + + } + void check (boolean val, String mes) { + if (!val) { + //p(name+" : "+mes); + throw new RuntimeException(name+" : "+mes); + } + } + + + HTTPDataCallback getCB (final String value, final String mes, final TestSettings settings) { + return new HTTPDataCallback() { + public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ + // if ("url".equals(mes)){ + // p("pos"+pos); + // p("len"+len); + // if (8==pos && 5 == len && "connect request".equals(name)) { + // //throw new RuntimeException(name); + // } + // } + //String str = str(b, pos, len); + ByteList list = settings.map.get(mes); + for (int i=0; i!=len; ++i) { + list.add(b.get(pos+i)); + } + //settings.map.put(mes, prev_val + str); + //check(value.equals(str), "incorrect "+mes+": "+str); + if (-1 == pos) { + throw new RuntimeException("he?"); + } + return 0; + } + }; + } + + void execute () { + p(name); + ByteBuffer buf = ByteBuffer.wrap(raw); + HTTPParser p = new HTTPParser(); + TestSettings s = settings(); + + + + p.execute(s, buf); + if (!p.upgrade) { + // call execute again, else parser can't know message is done + // if no content length is set. + p.execute(s, buf); + } + if (!s.success) { + throw new RuntimeException("Test: "+name+" failed"); + } + } // execute + + void execute_permutations() { + /* + |-|---------------| + |--|--------------| + |---|-------------| + (...) + |---------------|-| + |-----------------| + */ + p(name); + for (int i = 2; i != raw.length; ++i) { + // p(i); + HTTPParser p = new HTTPParser(); + TestSettings s = settings(); + ByteBuffer buf = ByteBuffer.wrap(raw); + int olimit = buf.limit(); + buf.limit(i); + + parse(p,s,buf); + if (!p.upgrade) { + buf.position(i); + buf.limit(olimit); + + parse(p,s,buf); + if (!p.upgrade) { + parse(p,s,buf); + } else { + if (!upgrade()) { + throw new RuntimeException("Test:"+name+"parsed as upgrade, is not"); + } + } + + } else { + if (!upgrade()) { + throw new RuntimeException("Test:"+name+"parsed as upgrade, is not"); + } + } + if (!s.success) { + p(this); + throw new RuntimeException("Test: "+name+" failed"); + } + reset(); + } + //System.exit(0); + } // execute_permutations + void parse(HTTPParser p, ParserSettings s, ByteBuffer b) { + //p("About to parse: "+b.position() + "->" + b.limit()); + p.execute(s, b); + } + + TestSettings settings() { + final TestSettings s = new TestSettings(); + s.on_url = getCB(request_url, "url", s); + s.on_message_begin = new HTTPCallback() { + public int cb (HTTPParser p) { + message_begin_called = true; + return -1; + } + }; + s.on_header_field = new HTTPDataCallback() { + public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ + if (null != currHValue && null == currHField) { + throw new RuntimeException(name+": shouldn't happen"); + } + if (null != currHField) { + if (null == currHValue) { + currHField += str(b,pos,len); + return 0; + } else { + parsed_header.put(currHField, currHValue); + currHField = null; + currHValue = null; + } + } + currHField = str(b,pos,len); + return 0; + } + }; + s.on_header_value = new HTTPDataCallback() { + public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ + if (null == currHField) { + throw new RuntimeException(name+" :shouldn't happen field"); + } + if (null == currHValue) { + currHValue = str(b,pos,len); + } else { + currHValue += str(b, pos, len); + } + return 0; + } + }; + s.on_headers_complete = new HTTPCallback() { + public int cb (HTTPParser p) { + headers_complete_called = true; + String parsed_path = null; + String parsed_query = null; + String parsed_url = null; + String parsed_frag = null; + + try { + parsed_url = new String(s.map.get("url").toArray(), "UTF8"); + + HTTPParserUrl u = new HTTPParserUrl(); + HTTPParser pp = new HTTPParser(); + ByteBuffer data = Util.buffer(parsed_url); + pp.parse_url(data,false, u); + + parsed_path = u.getFieldValue(HTTPParser.UrlFields.UF_PATH, data); + parsed_query = u.getFieldValue(HTTPParser.UrlFields.UF_QUERY, data); + parsed_frag = u.getFieldValue(HTTPParser.UrlFields.UF_FRAGMENT, data); + + } catch (java.io.UnsupportedEncodingException uee) { + throw new RuntimeException(uee); + } + + if (!request_path.equals(parsed_path)) { + throw new RuntimeException(name+": invalid path: "+parsed_path+" should be: "+request_path); + } + if (!query_string.equals(parsed_query)) { + throw new RuntimeException(name+": invalid query: "+parsed_query+" should be: "+query_string); + } + if (!request_url.equals(parsed_url)) { + throw new RuntimeException(">"+name+"<: invalid url: >"+parsed_url+"< should be: >"+request_url+"<"); + } + if (!fragment.equals(parsed_frag)) { + throw new RuntimeException(name+": invalid fragement: "+parsed_frag+" should be: "+fragment); + } + if (null != currHValue || null != currHField) { + if (null == currHField || null == currHValue) { + throw new RuntimeException("shouldn't happen"); + } + } + if (null != currHField) { + //p(currHField); + //p(">"+currHValue+"<"); + parsed_header.put(currHField, currHValue); + currHField = null; + currHValue = null; + } + + + return 0; + } + }; + // s.on_headers_complete = new HTTPCallback() { + // public int cb (HTTPParser p) { + // p("Complete:"+name); + // return 0; + // } + // }; + + s.on_body = new HTTPDataCallback() { + public int cb (HTTPParser p, ByteBuffer b, int pos, int len){ + int l = pbody == null ? len : len + pbody.length; + int off = pbody == null ? 0 : pbody.length; + byte [] nbody = new byte[l]; + + if (null != pbody) { + System.arraycopy(pbody, 0, nbody, 0, pbody.length); + } + + int saved = b.position(); + b.position(pos); + b.get(nbody, off, len); + b.position(saved); + pbody = nbody; + return 0; + } + }; + + s.on_message_complete = new HTTPCallback() { + public int cb(HTTPParser p) { + message_complete_called = true; + num_called += 1; + if ( p.http_minor != http_minor + || p.http_major != http_major + || p.status_code != status_code ) { + + throw new RuntimeException("major/minor/status_code mismatch"); + } + + //check headers + + if (header.keySet().size() != parsed_header.keySet().size()) { + p(parsed_header); + throw new RuntimeException(name+": different amount of headers"); + } + for (String key : header.keySet()) { + String pvalue = parsed_header.get(key); + if (!header.get(key).equals(pvalue)) { + throw new RuntimeException(name+" : different values for :"+key+" is >"+pvalue+"< should: >"+header.get(key)+"<"); + } + } + //check body + if (null == pbody && (null == body || body.length == 0 || body.length == 1)) { + s.success = true; + return 0; + } + if (null == pbody) { + throw new RuntimeException(name+": no body, should be: "+new String(body)); + } + if (pbody.length != body.length) { + p(pbody.length); + p(body.length); + p(new String(pbody)); + p(new String(body)); + throw new RuntimeException(name+": incorrect body length"); + } + for (int i = 0 ; i!= body.length; ++i) { + if (pbody[i] != body[i]) { + throw new RuntimeException("different body"); + } + } + s.success = true; + return 0; + } + }; + return s; + } // settings + static void p(Object o) { + System.out.println(o); + } + + static class TestSettings extends ParserSettings { + public boolean success; + Map map; + TestSettings () { + map = new HashMap(); + map.put("path", new ByteList()); + map.put("query_string", new ByteList()); + map.put("url", new ByteList()); + map.put("fragment", new ByteList()); + } + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java new file mode 100644 index 0000000..0e74021 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java @@ -0,0 +1,51 @@ +package http_parser.lolevel; + +import http_parser.HTTPParserUrl; +import static http_parser.lolevel.Util.*; + +public class ParseUrl { + public static void test(int i) { + HTTPParserUrl u = new HTTPParserUrl(); + HTTPParser p = new HTTPParser(); + Url test = Url.URL_TESTS[i]; +// System.out.println(":: " + test.name); + int rv = p.parse_url(Util.buffer(test.url),test.is_connect,u); + UnitTest.check_equals(rv, test.rv); + if(test.rv == 0){ + UnitTest.check_equals(u, test.u); + } + + } + public static void test() { + p(ParseUrl.class); + + for (int i = 0; i < Url.URL_TESTS.length; i++) { + test(i); + } + } + + static void usage() { + p("usage: [jre] http_parser.lolevel.ParseUrl [i]"); + p(" i : optional test case id"); + p("---------------------------------------------"); + p("Test Cases:"); + for (int i =0; i!= Url.URL_TESTS.length; ++i) { + p(" "+i+": "+Url.URL_TESTS[i].name); + } + } + + public static void main (String [] args) { + if (0 == args.length) { + test(); + } else { + try { + int i = Integer.parseInt(args[0]); + test(i); + } catch (Throwable t) { + t.printStackTrace(); + usage(); + } + + } + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java new file mode 100644 index 0000000..4367bbb --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java @@ -0,0 +1,69 @@ +package http_parser.lolevel; + +import java.nio.*; +import java.util.*; + +import static http_parser.lolevel.Util.*; +import http_parser.*; + +import primitive.collection.ByteList; + +public class Requests { + + static void test_simple(String req, boolean should_pass) { + HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST); + ByteBuffer buf = buffer(req); + boolean passed = false; + int read = 0; + try { + parser.execute(Util.SETTINGS_NULL, buf); + passed = (read == req.length()); + read = parser.execute(Util.SETTINGS_NULL, Util.empty()); + passed &= (0 == read); + } catch (Throwable t) { + passed = false; + } + check(passed == should_pass); + } + static void simple_tests() { + test_simple("hello world", false); + test_simple("GET / HTP/1.1\r\n\r\n", false); + + test_simple("ASDF / HTTP/1.1\r\n\r\n", false); + test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", false); + test_simple("GETA / HTTP/1.1\r\n\r\n", false); + } + + public static void test () { + p(Requests.class); + simple_tests(); + + List all = TestLoaderNG.load("tests.dumped"); + List requests = new LinkedList(); + for (Message m : all) { + if (ParserType.HTTP_REQUEST == m.type) { + requests.add(m); + } + } + for (Message m : requests) { + test_message(m); + } + + for (int i = 0; i!= requests.size(); ++i) { + if (!requests.get(i).should_keep_alive) continue; + for (int j = 0; j!=requests.size(); ++j) { + if (!requests.get(j).should_keep_alive) continue; + for (int k = 0; k!= requests.size(); ++k) { + test_multiple3(requests.get(i), requests.get(j), requests.get(k)); + } + } + } + + // postpone test_scan + + } + + + + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java new file mode 100644 index 0000000..1cb71dc --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java @@ -0,0 +1,52 @@ +package http_parser.lolevel; + +import java.nio.*; +import java.util.*; + +import static http_parser.lolevel.Util.*; +import http_parser.*; + +import primitive.collection.ByteList; + +public class Responses { + + + + public static void test () { + p(Responses.class); + List all = TestLoaderNG.load("tests.dumped"); + List responses = new LinkedList(); + for (Message m : all) { + if (ParserType.HTTP_RESPONSE == m.type) { + responses.add(m); + } + } + for (Message m : responses) { + test_message(m); + } + + for (int i = 0; i!= responses.size(); ++i) { + if (!responses.get(i).should_keep_alive) continue; + for (int j = 0; j!=responses.size(); ++j) { + if (!responses.get(j).should_keep_alive) continue; + for (int k = 0; k!= responses.size(); ++k) { + test_multiple3(responses.get(i), responses.get(j), responses.get(k)); + } + } + } + + // not sure what test_message_count_body does that test_message doesn't... + // Message m = find(responses, "404 no headers no body"); + // test_message_count_body(m); + // m = find(responses, "200 trailing space on chunked body"); + // test_message_count_body(m); + + // TODO test very large chunked response + + // test_scan is more or less the same as test_permutations, will implement later... + } + + + + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java new file mode 100644 index 0000000..6c35898 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java @@ -0,0 +1,16 @@ +package http_parser.lolevel; + + +public class Test { + public static void main (String [] args) { + UnitTest.test(); + TestHeaderOverflowError.test(); + TestNoOverflowLongBody.test(); + Responses.test(); + ParseUrl.test(); + Requests.test(); + Upgrade.test(); + WrongContentLength.test(); + } + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java new file mode 100644 index 0000000..ee47903 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java @@ -0,0 +1,48 @@ +package http_parser.lolevel; + +import java.nio.*; + +import static http_parser.lolevel.Util.*; + +public class TestHeaderOverflowError { + + public static void test (http_parser.ParserType type) { + HTTPParser parser = new HTTPParser(type); + ByteBuffer buf = getBytes(type); + + int numbytes = buf.limit(); + + parser.execute(Util.SETTINGS_NULL, buf); + + check(numbytes == buf.position()); + + buf = buffer("header-key: header-value\r\n"); + numbytes = buf.limit(); + for (int i = 0; i!= 1000; ++i) { + parser.execute(Util.SETTINGS_NULL, buf); + check(numbytes == buf.position()); + + buf.rewind(); + + } + } + + static ByteBuffer getBytes (http_parser.ParserType type) { + if (http_parser.ParserType.HTTP_BOTH == type) { + throw new RuntimeException("only HTTP_REQUEST and HTTP_RESPONSE"); + } + + if (http_parser.ParserType.HTTP_REQUEST == type) { + return buffer("GET / HTTP/1.1\r\n"); + } + return buffer("HTTP/1.0 200 OK\r\n"); + } + + public static void test () { + p(TestHeaderOverflowError.class); + test(http_parser.ParserType.HTTP_REQUEST); + test(http_parser.ParserType.HTTP_RESPONSE); + } + + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java new file mode 100644 index 0000000..329485d --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java @@ -0,0 +1,212 @@ +package http_parser.lolevel; +// name : 200 trailing space on chunked body +// raw : "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n25 \r\nThis is the data in the first chunk\r\n\r\n1C\r\nand this is the second one\r\n\r\n0 \r\n\r\n" +// type : HTTP_RESPONSE +// method: HTTP_DELETE +// status code :200 +// request_path: +// request_url : +// fragment : +// query_string: +// body :"This is the data in the first chunk\r\nand this is the second one\r\n" +// body_size :65 +// header_0 :{ "Content-Type": "text/plain"} +// header_1 :{ "Transfer-Encoding": "chunked"} +// should_keep_alive :1 +// upgrade :0 +// http_major :1 +// http_minor :1 + + +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.StringReader; +import java.io.Reader; +import java.io.Reader; +import java.io.IOException; + +import java.util.*; +import java.util.regex.*; + +import java.nio.ByteBuffer; + +import http_parser.HTTPMethod; +import http_parser.ParserType; + +public class TestLoaderNG { + String fn; + public TestLoaderNG(String filename) { + this.fn = filename; + } + static void p(Object o) { + System.out.println(o); + } + public static List load (String fn) { + List list = null; + try { + BufferedReader buf = new BufferedReader(new FileReader(fn)); + list = load(buf); + } catch (Throwable t) { + throw new RuntimeException(t); + } + return list; + + } + public static Message parse (String message) { + List list = load(new BufferedReader(new StringReader(message))); + if (null == list || 0 == list.size() ) { + return null; + } + return list.get(0); + } + + public static List load (BufferedReader buf) { + List list = new LinkedList(); + String line = null; + Message curr = new Message(); + Pattern pattern = Pattern.compile("(\\S+)\\s*:(.*)"); + try { + while (null != (line = buf.readLine()) ){ + if ("".equals(line.trim())) { + list.add (curr); + curr = new Message(); + continue; + } + Matcher m = pattern.matcher(line); + if (m.matches()) { + // you can not be fucking serious!? + // this has got to be the most retarded regex + // interface in the history of the world ... + // (though I'm sure there's worse c++ regexp libs...) + MatchResult r = m.toMatchResult(); + String key = r.group(1).trim(); + String value = r.group(2).trim(); + if ("name".equals(key)) {curr.name = value;} + else if ("raw".equals(key)) {curr.raw = toByteArray(value);} //! + else if ("type".equals(key)) {curr.type = ParserType.parse(value);} + else if ("method".equals(key)) {curr.method = HTTPMethod.parse(value);} + else if ("status_code".equals(key)) {curr.status_code = Integer.parseInt(value);} + else if ("request_path".equals(key)) {curr.request_path = value;} + else if ("request_url".equals(key)) {curr.request_url = value;} + + else if ("fragment".equals(key)) {curr.fragment = value;} + else if ("query_string".equals(key)) {curr.query_string = value;} + else if ("body".equals(key)) {curr.body = toByteArray(value);} //! + else if ("body_size".equals(key)) {curr.body_size = Integer.parseInt(value);} + else if (key.startsWith("header")) { + String [] h = getHeader(value); + curr.header.put(h[0], h[1]); + } + else if ("should_keep_alive".equals(key)) + {curr.should_keep_alive = (1 == Integer.parseInt(value));} + else if ("upgrade".equals(key)) { curr.upgrade = toByteArray(value);} + else if ("http_major".equals(key)) {curr.http_major = Integer.parseInt(value);} + else if ("http_minor".equals(key)) {curr.http_minor = Integer.parseInt(value);} + } else { + p("WTF?"+line); + } + + } + } catch (Throwable t) { + throw new RuntimeException(t); + } + return list; + } + + static String [] getHeader(String value) { + // { "Host": "0.0.0.0=5000"} + Pattern p = Pattern.compile("\\{ ?\"([^\"]*)\": ?\"(.*)\"}"); + Matcher m = p.matcher(value); + if (!m.matches()) { + p(value); + throw new RuntimeException("something wrong"); + } + String [] result = new String[2]; + MatchResult r = m.toMatchResult(); + result[0] = r.group(1).trim(); + result[1] = r.group(2); //.trim(); + return result; + } + + static final byte BSLASH = 0x5c; + static final byte QUOT = 0x22; + static final byte CR = 0x0d; + static final byte LF = 0x0a; + static final byte n = 0x6e; + static final byte r = 0x72; + + static final Byte[] JAVA_GENERICS_ROCK_HARD = new Byte[0]; + + + static byte [] toByteArray (String quotedString) { + ArrayList bytes = new ArrayList(); + String s = quotedString.substring(1, quotedString.length()-1); + byte [] byts = s.getBytes(java.nio.charset.Charset.forName("UTF8")); + boolean escaped = false; + for (byte b : byts) { + switch (b) { + case BSLASH: + escaped = true; + break; + case n: + if (escaped) { + bytes.add(LF); + escaped = false; + } else { + bytes.add(b); + } + break; + case r: + if (escaped) { + escaped = false; + bytes.add(CR); + } else { + bytes.add(b); + } + break; + case QUOT: + escaped = false; + bytes.add(QUOT); + break; + default: + bytes.add(b); + } + + } + + byts = new byte[bytes.size()]; + int i = 0; + for (Byte b : bytes) { + byts[i++]=b; + } + return byts; + } + + public static void main(String [] args) throws Throwable { + //TestLoaderNG l = new TestLoaderNG(args[0]); + List ts = load(args[0]); + for (Message t : ts) { +// for (int i =0; i!= t.raw.length; ++i) { +// p(i+":"+t.raw[i]); +// } +// try { + t.execute_permutations(); +// } catch (Throwable th) { +// p("failed: "+t.name); +// } + t.execute(); + // System.exit(0); + } + } + + class Header { + String field; + String value; + } + enum LastHeader { + NONE + ,FIELD + ,VALUE + } + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java new file mode 100644 index 0000000..13d8ea0 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java @@ -0,0 +1,62 @@ +package http_parser.lolevel; + +import java.nio.*; + +import static http_parser.lolevel.Util.*; + +public class TestNoOverflowLongBody { + + public static void test (http_parser.ParserType type, int len) { + HTTPParser parser = new HTTPParser(type); + ByteBuffer buf = getBytes(type, len); + + int buflen = buf.limit(); + + parser.execute(Util.SETTINGS_NULL, buf); + + check(buflen == buf.position()); + + buf = buffer("a"); + buflen = buf.limit(); + + for (int i = 0; i!= len; ++i) { + parser.execute(Util.SETTINGS_NULL, buf); + check(buflen == buf.position()); + buf.rewind(); + } + + buf = getBytes(type, len); + buflen = buf.limit(); + + parser.execute(Util.SETTINGS_NULL, buf); + + check(buflen == buf.position()); + + } + + static ByteBuffer getBytes (http_parser.ParserType type, int length) { + if (http_parser.ParserType.HTTP_BOTH == type) { + throw new RuntimeException("only HTTP_REQUEST and HTTP_RESPONSE"); + } + + String template = "%s\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n"; + String str = null; + if (http_parser.ParserType.HTTP_REQUEST == type) { + str = String.format(template, "GET / HTTP/1.1", length); + } else { + str = String.format(template, "HTTP/1.0 200 OK", length); + } + return buffer(str); + } + + public static void test () { + p(TestNoOverflowLongBody.class); + test(http_parser.ParserType.HTTP_REQUEST, 1000); + test(http_parser.ParserType.HTTP_REQUEST, 100000); + test(http_parser.ParserType.HTTP_RESPONSE, 1000); + test(http_parser.ParserType.HTTP_RESPONSE, 100000); + } + + + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java new file mode 100644 index 0000000..4159980 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java @@ -0,0 +1,117 @@ +package http_parser.lolevel; + +import java.nio.ByteBuffer; +import http_parser.HTTPException; +import http_parser.Util; + +public class UnitTest { + + static void p(Object o) {System.out.println(o);} + + public static void testErrorFormat() { + String bla = "This has an error in position 10 (the n in 'an')"; + ByteBuffer buf = ByteBuffer.wrap(bla.getBytes()); + buf.position(10); + + String mes = +"This has an error in position 10 (the n in 'an')\n" + +"..........^"; + + check_equals(mes, Util.error ("test error", buf, 0)); + + + bla = "123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J"; + buf = ByteBuffer.wrap(bla.getBytes()); + buf.position(50); + mes = +"56789B123456789C123456789D123456789E123456789F123456789G123456789H123456\n"+ +"....................................^"; + check_equals(mes, Util.error("test trim right and left", buf, 0)); + + + buf.position(5); + mes = +"123456789A123456789B123456789C123456789D123456789E123456789F123456789G12\n"+ +".....^"; + check_equals(mes, Util.error("test trim right", buf, 0)); + + + int limit = buf.limit(); + buf.limit(10); + mes = +"123456789A\n"+ +".....^"; + check_equals(mes, Util.error("all before, not enough after", buf, 0)); + + + + buf.limit(limit); + buf.position(90); + mes = +"9C123456789D123456789E123456789F123456789G123456789H123456789I123456789J\n"+ +"..............................................................^"; + check_equals(mes, Util.error("test trim left", buf, 10)); + } + + + // Test that the error callbacks are properly called. + public static void testErrorCallback () { + String nothttp = "THis is certainly not valid HTTP"; + ByteBuffer buf = ByteBuffer.wrap(nothttp.getBytes()); + + ParserSettings s = new ParserSettings(); + s.on_error = new HTTPErrorCallback() { + public void cb (HTTPParser p, String mes, ByteBuffer buf, int pos) { + throw new HTTPException(mes); + } + }; // err callback + + + HTTPParser p = new HTTPParser(); + try { + p.execute(s, buf); + } catch (HTTPException e) { + check_equals("Invalid HTTP method", e.getMessage()); + } + + buf = ByteBuffer.wrap("GET / HTTP 1.10000".getBytes()); + p = new HTTPParser(); + try { + p.execute(s, buf); + } catch (HTTPException e) { + check_equals("ridiculous http minor", e.getMessage()); + } + + // if no error handler is defined, behave just like the above... + ParserSettings s0 = new ParserSettings(); + + buf = ByteBuffer.wrap("THis is certainly not valid HTTP".getBytes()); + p = new HTTPParser(); + try { + p.execute(s0, buf); + } catch (HTTPException e) { + check_equals("Invalid HTTP method", e.getMessage()); + } + + buf = ByteBuffer.wrap("GET / HTTP 1.10000".getBytes()); + p = new HTTPParser(); + try { + p.execute(s0, buf); + } catch (HTTPException e) { + check_equals("ridiculous http minor", e.getMessage()); + } + } + + static void check_equals(Object supposed2be, Object is) { + if (!supposed2be.equals(is)) { + throw new RuntimeException(is + " is supposed to be "+supposed2be); + } + } + + + public static void test () { + p(UnitTest.class); + testErrorFormat(); + testErrorCallback(); + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java new file mode 100644 index 0000000..9af3d4a --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java @@ -0,0 +1,27 @@ +package http_parser.lolevel; + +import java.nio.*; +import java.util.*; + +import http_parser.ParserType; + +import static http_parser.lolevel.Util.*; + +public class Upgrade { + static final String upgrade = "GET /demo HTTP/1.1\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: WebSocket\r\n\r\n" + + "third key data"; + static void test () { + p(Upgrade.class); + HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST); + ByteBuffer buf = buffer(upgrade); + + int read = parser.execute(Util.SETTINGS_NULL, buf); + check (63 == read); + String s = str(buf); + check ("third key data".equals(str(buf))); + + } + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java new file mode 100644 index 0000000..35469d1 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java @@ -0,0 +1,127 @@ +package http_parser.lolevel; + +import http_parser.FieldData; +import http_parser.HTTPParserUrl; + +import static http_parser.HTTPParserUrl.*; +import static http_parser.lolevel.HTTPParser.*; + +/** + */ +public class Url { + + public static Url[] URL_TESTS = new Url[]{ + new Url("proxy request", "http://hostname/", false, + new HTTPParserUrl( + (1 << UrlFields.UF_SCHEMA.getIndex()) | (1 << UrlFields.UF_HOST.getIndex()) | (1 << UrlFields.UF_PATH.getIndex()), + 0, + new FieldData[]{ + new FieldData(0,4), + new FieldData(7,8), + new FieldData(0,0), + new FieldData(15,1), + new FieldData(0,0), + new FieldData(0,0) + }), + 0), + new Url("CONNECT request", "hostname:443", true, + new HTTPParserUrl( + (1 << UrlFields.UF_HOST.getIndex()) | (1 << UrlFields.UF_PORT.getIndex()), + 443, + new FieldData[]{ + new FieldData(0,0), + new FieldData(0,8), + new FieldData(9,3), + new FieldData(0,0), + new FieldData(0,0), + new FieldData(0,0) + }), + 0), + new Url("proxy ipv6 request", "http://[1:2::3:4]/", false, + new HTTPParserUrl( + (1 << UrlFields.UF_SCHEMA.getIndex()) | (1 << UrlFields.UF_HOST.getIndex()) | (1 << UrlFields.UF_PATH.getIndex()), + 0, + new FieldData[]{ + new FieldData(0,4), + new FieldData(8,8), + new FieldData(0,0), + new FieldData(17,1), + new FieldData(0,0), + new FieldData(0,0) + }), + 0), + new Url("CONNECT ipv6 address", "[1:2::3:4]:443", true, + new HTTPParserUrl( + (1 << UrlFields.UF_HOST.getIndex()) | (1 << UrlFields.UF_PORT.getIndex()), + 443, + new FieldData[]{ + new FieldData(0,0), + new FieldData(1,8), + new FieldData(11,3), + new FieldData(0,0), + new FieldData(0,0), + new FieldData(0,0) + }), + 0), + new Url("extra ? in query string", + "http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css", + false, + new HTTPParserUrl( + (1 << UrlFields.UF_SCHEMA.getIndex()) | + (1 << UrlFields.UF_HOST.getIndex()) | + (1 << UrlFields.UF_PATH.getIndex()) | + (1 << UrlFields.UF_QUERY.getIndex()), + 0, + new FieldData[]{ + new FieldData(0,4), + new FieldData(7,10), + new FieldData(0,0), + new FieldData(17,12), + new FieldData(30,187), + new FieldData(0,0) + }), + 0), + new Url("proxy empty host", + "http://:443/", + false, + null, + 1), + new Url("proxy empty port", + "http://hostname:/", + false, + null, + 1), + new Url("CONNECT empty host", + ":443", + true, + null, + 1), + new Url("CONNECT empty port", + "hostname:", + true, + null, + 1), + new Url("CONNECT with extra bits", + "hostname:443/", + true, + null, + 1), + + }; + + String name; + String url; + boolean is_connect; + HTTPParserUrl u; + int rv; + + public Url(String name, String url, boolean is_connect, HTTPParserUrl u, int rv) { + this.name = name; + this.url = url; + this.is_connect = is_connect; + this.u = u; + this.rv = rv; + } + + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java new file mode 100644 index 0000000..c73d9e6 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java @@ -0,0 +1,236 @@ +package http_parser.lolevel; + +import java.nio.*; +import java.util.*; + +import primitive.collection.ByteList; + +import http_parser.*; + +public class Util { + + static final ParserSettings SETTINGS_NULL = new ParserSettings(); + + static String str (ByteBuffer b, int pos, int len) { + byte [] by = new byte[len]; + int saved = b.position(); + b.position(pos); + b.get(by); + b.position(saved); + return new String(by); + } + static String str (ByteBuffer b) { + int len = b.limit() - b.position(); + byte [] by = new byte[len]; + int saved = b.position(); + b.get(by); + b.position(saved); + return new String(by); + } + + static ByteBuffer buffer(String str) { + return ByteBuffer.wrap(str.getBytes()); + } + + static ByteBuffer empty() { + return ByteBuffer.wrap(new byte[0]); + } + + static void check(boolean betterBtrue) { + if (!betterBtrue) { + throw new RuntimeException("!"); + } + } + static void check (int should, int is) { + if (should != is) { + throw new RuntimeException("should be: "+should+" is:"+is); + } + } + + static void test_message(Message mes) { + int raw_len = mes.raw.length; + for (int msg1len = 0; msg1len != raw_len; ++msg1len) { + mes.reset(); + ByteBuffer msg1 = ByteBuffer.wrap(mes.raw, 0, msg1len); + ByteBuffer msg2 = ByteBuffer.wrap(mes.raw, msg1len, mes.raw.length - msg1len); + + HTTPParser parser = new HTTPParser(mes.type); + ParserSettings settings = mes.settings(); + + int read = 0; + if (msg1len !=0) { + read = parser.execute(settings, msg1); + if (mes.upgrade() && parser.upgrade) { + // Messages have a settings() that checks itself... + check(1 == mes.num_called); + continue; + } + check(read == msg1len); + } + + read = parser.execute(settings, msg2); + if (mes.upgrade() && parser.upgrade) { + check(1 == mes.num_called); + continue; + } + + check( mes.raw.length - msg1len, read); + + ByteBuffer empty = Util.empty(); + read = parser.execute(settings, empty); + + if (mes.upgrade() && parser.upgrade) { + check(1 == mes.num_called); + continue; + } + check(empty.position() == empty.limit()); + check(0 == read); + check(1 == mes.num_called); + + } + } + + static void test_multiple3(Message r1, Message r2, Message r3) { + int message_count = 1; + if (!r1.upgrade()) { + message_count++; + if (!r2.upgrade()) { + message_count++; + } + } + boolean has_upgrade = (message_count < 3 || r3.upgrade()); + + ByteList blist = new ByteList(); + blist.addAll(r1.raw); + blist.addAll(r2.raw); + blist.addAll(r3.raw); + + byte [] raw = blist.toArray(); + ByteBuffer buf = ByteBuffer.wrap(raw); + + Util.Settings settings = Util.settings(); + HTTPParser parser = new HTTPParser(r1.type); + + int read = parser.execute(settings, buf); + if (has_upgrade && parser.upgrade) { + raw = upgrade_message_fix(raw, read, r1,r2,r3); + check(settings.numCalled == message_count); + return; + } + + check(read == raw.length); + + buf = Util.empty(); + read = parser.execute(settings, buf); + if (has_upgrade && parser.upgrade) { + check(settings.numCalled == message_count); + return; + } + + check(0 == read); + check(settings.numCalled == message_count); + } + + /* Given a sequence of bytes and the number of these that we were able to + * parse, verify that upgrade bodies are correct. + */ + static byte [] upgrade_message_fix(byte[] body, int nread, Message... msgs) { + int off = 0; + for (Message m : msgs) { + off += m.raw.length; + if (m.upgrade()) { + off -= m.upgrade.length; + // Original C: + // Check the portion of the response after its specified upgrade + // if (!check_str_eq(m, "upgrade", body + off, body + nread)) { + // abort(); + // } + // to me, this seems to be equivalent to comparing off and nread ... + check (off, nread); + + // Original C: + // Fix up the response so that message_eq() will verify the beginning + // of the upgrade */ + // + // *(body + nread + strlen(m->upgrade)) = '\0'; + // This only shortens body so the strlen check passes. + return new byte[off]; + + } + } + return null; + } +//upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) { +// va_list ap; +// size_t i; +// size_t off = 0; +// +// va_start(ap, nmsgs); +// +// for (i = 0; i < nmsgs; i++) { +// struct message *m = va_arg(ap, struct message *); +// +// off += strlen(m->raw); +// +// if (m->upgrade) { +// off -= strlen(m->upgrade); +// +// /* Check the portion of the response after its specified upgrade */ +// if (!check_str_eq(m, "upgrade", body + off, body + nread)) { +// abort(); +// } +// +// /* Fix up the response so that message_eq() will verify the beginning +// * of the upgrade */ +// *(body + nread + strlen(m->upgrade)) = '\0'; +// messages[num_messages -1 ].upgrade = body + nread; +// +// va_end(ap); +// return; +// } +// } +// +// va_end(ap); +// printf("\n\n*** Error: expected a message with upgrade ***\n"); +// +// abort(); +//} + static void p (Object o) { + System.out.println(o); + } + + static Settings settings() { + return new Settings(); + } + static Message find(List list, String name) { + for (Message m : list) { + if (name.equals(m.name)) { + return m; + } + } + return null; + } + + static class Settings extends ParserSettings { + public int numCalled; + public int bodyCount; + Settings() { + this.on_message_complete = new HTTPCallback() { + public int cb (HTTPParser parser) { + numCalled++; + return 0; + } + }; + this.on_body = new HTTPDataCallback() { + public int cb (HTTPParser p, ByteBuffer b, int pos, int len) { + bodyCount += len; + return 0; + } + }; + } + + int numCalled () { + return this.numCalled; + } + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java new file mode 100644 index 0000000..fc8f081 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java @@ -0,0 +1,59 @@ +package http_parser.lolevel; + +import java.nio.*; +import java.util.*; + +import http_parser.ParserType; + +import static http_parser.lolevel.Util.*; + +public class WrongContentLength { + static final String contentLength = "GET / HTTP/1.0\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello" + + "hello_again"; + static void test () { + p(WrongContentLength.class); + HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST); + ByteBuffer buf = buffer(contentLength); + + Settings settings = new Settings(); + + int read = parser.execute(settings, buf); + check (settings.msg_cmplt_called); + check ("invalid method".equals(settings.err)); + + } + public static void main(String [] args) { + test(); + } + + static class Settings extends ParserSettings { + public int bodyCount; + public boolean msg_cmplt_called; + public String err; + Settings () { + this.on_message_complete = new HTTPCallback () { + public int cb (HTTPParser p) { + check (5 == bodyCount); + msg_cmplt_called = true; + return 0; + } + }; + this.on_body = new HTTPDataCallback() { + public int cb (HTTPParser p, ByteBuffer b, int pos, int len) { + bodyCount += len; + check ("hello".equals(str(b, pos, len))); + return 0; + } + }; + this.on_error = new HTTPErrorCallback() { + public void cb (HTTPParser p, String mes, ByteBuffer b, int i) { + err = mes; + } + }; + } + } + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/test.c b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/test.c new file mode 100644 index 0000000..3840747 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/test.c @@ -0,0 +1,3425 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "http_parser.h" +#include +#include +#include +#include /* rand */ +#include +#include + +#undef TRUE +#define TRUE 1 +#undef FALSE +#define FALSE 0 + +#define MAX_HEADERS 13 +#define MAX_ELEMENT_SIZE 2048 + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +static http_parser *parser; + +struct message { + const char *name; // for debugging purposes + const char *raw; + enum http_parser_type type; + enum http_method method; + int status_code; + char request_path[MAX_ELEMENT_SIZE]; + char request_url[MAX_ELEMENT_SIZE]; + char fragment[MAX_ELEMENT_SIZE]; + char query_string[MAX_ELEMENT_SIZE]; + char body[MAX_ELEMENT_SIZE]; + size_t body_size; + const char *host; + const char *userinfo; + uint16_t port; + int num_headers; + enum { NONE=0, FIELD, VALUE } last_header_element; + char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; + int should_keep_alive; + + const char *upgrade; // upgraded body + + unsigned short http_major; + unsigned short http_minor; + + int message_begin_cb_called; + int headers_complete_cb_called; + int message_complete_cb_called; + int message_complete_on_eof; + int body_is_final; +}; + +static int currently_parsing_eof; + +static struct message messages[5]; +static int num_messages; +static http_parser_settings *current_pause_parser; + +/* * R E Q U E S T S * */ +const struct message requests[] = +#define CURL_GET 0 +{ {.name= "curl get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.1\r\n" + "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= + { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" } + , { "Host", "0.0.0.0=5000" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +#define FIREFOX_GET 1 +, {.name= "firefox get" + ,.type= HTTP_REQUEST + ,.raw= "GET /favicon.ico HTTP/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: en-us,en;q=0.5\r\n" + "Accept-Encoding: gzip,deflate\r\n" + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" + "Keep-Alive: 300\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/favicon.ico" + ,.request_url= "/favicon.ico" + ,.num_headers= 8 + ,.headers= + { { "Host", "0.0.0.0=5000" } + , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" } + , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" } + , { "Accept-Language", "en-us,en;q=0.5" } + , { "Accept-Encoding", "gzip,deflate" } + , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" } + , { "Keep-Alive", "300" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +#define DUMBFUCK 2 +, {.name= "dumbfuck" + ,.type= HTTP_REQUEST + ,.raw= "GET /dumbfuck HTTP/1.1\r\n" + "aaaaaaaaaaaaa:++++++++++\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/dumbfuck" + ,.request_url= "/dumbfuck" + ,.num_headers= 1 + ,.headers= + { { "aaaaaaaaaaaaa", "++++++++++" } + } + ,.body= "" + } + +#define FRAGMENT_IN_URI 3 +, {.name= "fragment in url" + ,.type= HTTP_REQUEST + ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "page=1" + ,.fragment= "posts-17408" + ,.request_path= "/forums/1/topics/2375" + /* XXX request url does include fragment? */ + ,.request_url= "/forums/1/topics/2375?page=1#posts-17408" + ,.num_headers= 0 + ,.body= "" + } + +#define GET_NO_HEADERS_NO_BODY 4 +, {.name= "get no headers no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_no_headers_no_body/world" + ,.request_url= "/get_no_headers_no_body/world" + ,.num_headers= 0 + ,.body= "" + } + +#define GET_ONE_HEADER_NO_BODY 5 +, {.name= "get one header no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_one_header_no_body" + ,.request_url= "/get_one_header_no_body" + ,.num_headers= 1 + ,.headers= + { { "Accept" , "*/*" } + } + ,.body= "" + } + +#define GET_FUNKY_CONTENT_LENGTH 6 +, {.name= "get funky content length body hello" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" + "conTENT-Length: 5\r\n" + "\r\n" + "HELLO" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_funky_content_length_body_hello" + ,.request_url= "/get_funky_content_length_body_hello" + ,.num_headers= 1 + ,.headers= + { { "conTENT-Length" , "5" } + } + ,.body= "HELLO" + } + +#define POST_IDENTITY_BODY_WORLD 7 +, {.name= "post identity body world" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" + "Accept: */*\r\n" + "Transfer-Encoding: identity\r\n" + "Content-Length: 5\r\n" + "\r\n" + "World" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "q=search" + ,.fragment= "hey" + ,.request_path= "/post_identity_body_world" + ,.request_url= "/post_identity_body_world?q=search#hey" + ,.num_headers= 3 + ,.headers= + { { "Accept", "*/*" } + , { "Transfer-Encoding", "identity" } + , { "Content-Length", "5" } + } + ,.body= "World" + } + +#define POST_CHUNKED_ALL_YOUR_BASE 8 +, {.name= "post - chunked body: all your base are belong to us" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "1e\r\nall your base are belong to us\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/post_chunked_all_your_base" + ,.request_url= "/post_chunked_all_your_base" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding" , "chunked" } + } + ,.body= "all your base are belong to us" + } + +#define TWO_CHUNKS_MULT_ZERO_END 9 +, {.name= "two chunks ; triple zero ending" + ,.type= HTTP_REQUEST + ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "000\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/two_chunks_mult_zero_end" + ,.request_url= "/two_chunks_mult_zero_end" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +#define CHUNKED_W_TRAILING_HEADERS 10 +, {.name= "chunked with trailing headers. blech." + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "0\r\n" + "Vary: *\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_trailing_headers" + ,.request_url= "/chunked_w_trailing_headers" + ,.num_headers= 3 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Vary", "*" } + , { "Content-Type", "text/plain" } + } + ,.body= "hello world" + } + +#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 +, {.name= "with bullshit after the length" + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n" + "6; blahblah; blah\r\n world\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_bullshit_after_length" + ,.request_url= "/chunked_w_bullshit_after_length" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +#define WITH_QUOTES 12 +, {.name= "with quotes" + ,.type= HTTP_REQUEST + ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "foo=\"bar\"" + ,.fragment= "" + ,.request_path= "/with_\"stupid\"_quotes" + ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\"" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define APACHEBENCH_GET 13 +/* The server receiving this request SHOULD NOT wait for EOF + * to know that content-length == 0. + * How to represent this in a unit test? message_complete_on_eof + * Compare with NO_CONTENT_LENGTH_RESPONSE. + */ +, {.name = "apachebench get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.0\r\n" + "Host: 0.0.0.0:5000\r\n" + "User-Agent: ApacheBench/2.3\r\n" + "Accept: */*\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= { { "Host", "0.0.0.0:5000" } + , { "User-Agent", "ApacheBench/2.3" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +#define QUERY_URL_WITH_QUESTION_MARK_GET 14 +/* Some clients include '?' characters in query strings. + */ +, {.name = "query url with question mark" + ,.type= HTTP_REQUEST + ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "foo=bar?baz" + ,.fragment= "" + ,.request_path= "/test.cgi" + ,.request_url= "/test.cgi?foo=bar?baz" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define PREFIX_NEWLINE_GET 15 +/* Some clients, especially after a POST in a keep-alive connection, + * will send an extra CRLF before the next request + */ +, {.name = "newline prefix get" + ,.type= HTTP_REQUEST + ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define UPGRADE_REQUEST 16 +, {.name = "upgrade request" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Upgrade: WebSocket\r\n" + "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" + "Origin: http://example.com\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 7 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Host", "example.com" } + , { "Connection", "Upgrade" } + , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" } + , { "Sec-WebSocket-Protocol", "sample" } + , { "Upgrade", "WebSocket" } + , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" } + , { "Origin", "http://example.com" } + } + ,.body= "" + } + +#define CONNECT_REQUEST 17 +, {.name = "connect request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + "some data\r\n" + "and yet even more data" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "0-home0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade="some data\r\nand yet even more data" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +#define REPORT_REQ 18 +, {.name= "report request" + ,.type= HTTP_REQUEST + ,.raw= "REPORT /test HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_REPORT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define NO_HTTP_VERSION 19 +, {.name= "request with no http version" + ,.type= HTTP_REQUEST + ,.raw= "GET /\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 0 + ,.http_minor= 9 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define MSEARCH_REQ 20 +, {.name= "m-search request" + ,.type= HTTP_REQUEST + ,.raw= "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "ST: \"ssdp:all\"\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_MSEARCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "*" + ,.request_url= "*" + ,.num_headers= 3 + ,.headers= { { "HOST", "239.255.255.250:1900" } + , { "MAN", "\"ssdp:discover\"" } + , { "ST", "\"ssdp:all\"" } + } + ,.body= "" + } + +#define LINE_FOLDING_IN_HEADER 21 +, {.name= "line folding in header value" + ,.type= HTTP_REQUEST + ,.raw= "GET / HTTP/1.1\r\n" + "Line1: abc\r\n" + "\tdef\r\n" + " ghi\r\n" + "\t\tjkl\r\n" + " mno \r\n" + "\t \tqrs\r\n" + "Line2: \t line2\t\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 2 + ,.headers= { { "Line1", "abcdefghijklmno qrs" } + , { "Line2", "line2\t" } + } + ,.body= "" + } + + +#define QUERY_TERMINATED_HOST 22 +, {.name= "host terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org?hail=all" + ,.host= "hypnotoad.org" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define QUERY_TERMINATED_HOSTPORT 23 +, {.name= "host:port terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234?hail=all" + ,.host= "hypnotoad.org" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define SPACE_TERMINATED_HOSTPORT 24 +, {.name= "host:port terminated by a space" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234" + ,.host= "hypnotoad.org" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define PATCH_REQ 25 +, {.name = "PATCH request" + ,.type= HTTP_REQUEST + ,.raw= "PATCH /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/example\r\n" + "If-Match: \"e0023aa4e\"\r\n" + "Content-Length: 10\r\n" + "\r\n" + "cccccccccc" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PATCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 4 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/example" } + , { "If-Match", "\"e0023aa4e\"" } + , { "Content-Length", "10" } + } + ,.body= "cccccccccc" + } + +#define CONNECT_CAPS_REQUEST 26 +, {.name = "connect caps request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "HOME0.NETSCAPE.COM:443" + ,.num_headers= 2 + ,.upgrade="" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +#if !HTTP_PARSER_STRICT +#define UTF8_PATH_REQ 27 +, {.name= "utf-8 path request" + ,.type= HTTP_REQUEST + ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n" + "Host: github.com\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "q=1" + ,.fragment= "narf" + ,.request_path= "/δ¶/δt/pope" + ,.request_url= "/δ¶/δt/pope?q=1#narf" + ,.num_headers= 1 + ,.headers= { {"Host", "github.com" } + } + ,.body= "" + } + +#define HOSTNAME_UNDERSCORE 28 +, {.name = "hostname underscore" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "home_0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade="" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } +#endif /* !HTTP_PARSER_STRICT */ + +/* see https://github.com/ry/http-parser/issues/47 */ +#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29 +, {.name = "eat CRLF between requests, no \"Connection: close\" header" + ,.raw= "POST / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 4\r\n" + "\r\n" + "q=42\r\n" /* note the trailing CRLF */ + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 3 + ,.upgrade= 0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/x-www-form-urlencoded" } + , { "Content-Length", "4" } + } + ,.body= "q=42" + } + +/* see https://github.com/ry/http-parser/issues/47 */ +#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30 +, {.name = "eat CRLF between requests even if \"Connection: close\" is set" + ,.raw= "POST / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 4\r\n" + "Connection: close\r\n" + "\r\n" + "q=42\r\n" /* note the trailing CRLF */ + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 4 + ,.upgrade= 0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/x-www-form-urlencoded" } + , { "Content-Length", "4" } + , { "Connection", "close" } + } + ,.body= "q=42" + } + +#define PURGE_REQ 31 +, {.name = "PURGE request" + ,.type= HTTP_REQUEST + ,.raw= "PURGE /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PURGE + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 1 + ,.headers= { { "Host", "www.example.com" } } + ,.body= "" + } + +#define SEARCH_REQ 32 +, {.name = "SEARCH request" + ,.type= HTTP_REQUEST + ,.raw= "SEARCH / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_SEARCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 1 + ,.headers= { { "Host", "www.example.com" } } + ,.body= "" + } + +#define PROXY_WITH_BASIC_AUTH 33 +, {.name= "host:port and basic_auth" + ,.type= HTTP_REQUEST + ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.fragment= "" + ,.request_path= "/toto" + ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto" + ,.host= "hypnotoad.org" + ,.userinfo= "a%12:b!&*$" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + + +, {.name= NULL } /* sentinel */ +}; + +/* * R E S P O N S E S * */ +const struct message responses[] = +#define GOOGLE_301 0 +{ {.name= "google 301" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301 Moved Permanently\r\n" + "Location: http://www.google.com/\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n" + "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n" + "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */ + "Cache-Control: public, max-age=2592000\r\n" + "Server: gws\r\n" + "Content-Length: 219 \r\n" + "\r\n" + "\n" + "301 Moved\n" + "

    301 Moved

    \n" + "The document has moved\n" + "
    here.\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.num_headers= 8 + ,.headers= + { { "Location", "http://www.google.com/" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" } + , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" } + , { "X-$PrototypeBI-Version", "1.6.0.3" } + , { "Cache-Control", "public, max-age=2592000" } + , { "Server", "gws" } + , { "Content-Length", "219 " } + } + ,.body= "\n" + "301 Moved\n" + "

    301 Moved

    \n" + "The document has moved\n" + "here.\r\n" + "\r\n" + } + +#define NO_CONTENT_LENGTH_RESPONSE 1 +/* The client should wait for the server's EOF. That is, when content-length + * is not specified, and "Connection: close", the end of body is specified + * by the EOF. + * Compare with APACHEBENCH_GET + */ +, {.name= "no content-length response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" + "Server: Apache\r\n" + "X-Powered-By: Servlet/2.5 JSP/2.1\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" + "Connection: close\r\n" + "\r\n" + "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 5 + ,.headers= + { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" } + , { "Server", "Apache" } + , { "X-Powered-By", "Servlet/2.5 JSP/2.1" } + , { "Content-Type", "text/xml; charset=utf-8" } + , { "Connection", "close" } + } + ,.body= "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + } + +#define NO_HEADERS_NO_BODY_404 2 +, {.name= "404 no headers no body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 404 + ,.num_headers= 0 + ,.headers= {} + ,.body_size= 0 + ,.body= "" + } + +#define NO_REASON_PHRASE 3 +, {.name= "301 no response phrase" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301\r\n\r\n" + ,.should_keep_alive = FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define TRAILING_SPACE_ON_CHUNKED_BODY 4 +, {.name="200 trailing space on chunked body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "25 \r\n" + "This is the data in the first chunk\r\n" + "\r\n" + "1C\r\n" + "and this is the second one\r\n" + "\r\n" + "0 \r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/plain" } + , {"Transfer-Encoding", "chunked" } + } + ,.body_size = 37+28 + ,.body = + "This is the data in the first chunk\r\n" + "and this is the second one\r\n" + + } + +#define NO_CARRIAGE_RET 5 +, {.name="no carriage ret" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\n" + "Content-Type: text/html; charset=utf-8\n" + "Connection: close\n" + "\n" + "these headers are from http://news.ycombinator.com/" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/html; charset=utf-8" } + , {"Connection", "close" } + } + ,.body= "these headers are from http://news.ycombinator.com/" + } + +#define PROXY_CONNECTION 6 +, {.name="proxy connection" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Content-Length: 11\r\n" + "Proxy-Connection: close\r\n" + "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 4 + ,.headers= + { {"Content-Type", "text/html; charset=UTF-8" } + , {"Content-Length", "11" } + , {"Proxy-Connection", "close" } + , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"} + } + ,.body= "hello world" + } + +#define UNDERSTORE_HEADER_KEY 7 + // shown by + // curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;" +, {.name="underscore header key" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Server: DCLK-AdSvr\r\n" + "Content-Type: text/xml\r\n" + "Content-Length: 0\r\n" + "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 4 + ,.headers= + { {"Server", "DCLK-AdSvr" } + , {"Content-Type", "text/xml" } + , {"Content-Length", "0" } + , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" } + } + ,.body= "" + } + +#define BONJOUR_MADAME_FR 8 +/* The client should not merge two headers fields when the first one doesn't + * have a value. + */ +, {.name= "bonjourmadame.fr" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 301 Moved Permanently\r\n" + "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n" + "Server: Apache/2.2.3 (Red Hat)\r\n" + "Cache-Control: public\r\n" + "Pragma: \r\n" + "Location: http://www.bonjourmadame.fr/\r\n" + "Vary: Accept-Encoding\r\n" + "Content-Length: 0\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 301 + ,.num_headers= 9 + ,.headers= + { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" } + , { "Server", "Apache/2.2.3 (Red Hat)" } + , { "Cache-Control", "public" } + , { "Pragma", "" } + , { "Location", "http://www.bonjourmadame.fr/" } + , { "Vary", "Accept-Encoding" } + , { "Content-Length", "0" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +#define RES_FIELD_UNDERSCORE 9 +/* Should handle spaces in header fields */ +, {.name= "field underscore" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n" + "Server: Apache\r\n" + "Cache-Control: no-cache, must-revalidate\r\n" + "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" + ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n" + "Vary: Accept-Encoding\r\n" + "_eep-Alive: timeout=45\r\n" /* semantic value ignored */ + "_onnection: Keep-Alive\r\n" /* semantic value ignored */ + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "0\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 11 + ,.headers= + { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" } + , { "Server", "Apache" } + , { "Cache-Control", "no-cache, must-revalidate" } + , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" } + , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" } + , { "Vary", "Accept-Encoding" } + , { "_eep-Alive", "timeout=45" } + , { "_onnection", "Keep-Alive" } + , { "Transfer-Encoding", "chunked" } + , { "Content-Type", "text/html" } + , { "Connection", "close" } + } + ,.body= "" + } + +#define NON_ASCII_IN_STATUS_LINE 10 +/* Should handle non-ASCII in status line */ +, {.name= "non-ASCII in status line" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n" + "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 500 + ,.num_headers= 3 + ,.headers= + { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" } + , { "Content-Length", "0" } + , { "Connection", "close" } + } + ,.body= "" + } + +#define HTTP_VERSION_0_9 11 +/* Should handle HTTP/0.9 */ +, {.name= "http version 0.9" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/0.9 200 OK\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 0 + ,.http_minor= 9 + ,.status_code= 200 + ,.num_headers= 0 + ,.headers= + {} + ,.body= "" + } + +#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12 +/* The client should wait for the server's EOF. That is, when neither + * content-length nor transfer-encoding is specified, the end of body + * is specified by the EOF. + */ +, {.name= "neither content-length nor transfer-encoding response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Content-Type", "text/plain" } + } + ,.body= "hello world" + } + +#define NO_BODY_HTTP10_KA_200 13 +, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 200 OK\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Connection", "keep-alive" } + } + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP10_KA_204 14 +, {.name= "HTTP/1.0 with keep-alive and a 204 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 204 No content\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 204 + ,.num_headers= 1 + ,.headers= + { { "Connection", "keep-alive" } + } + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_KA_200 15 +, {.name= "HTTP/1.1 with an EOF-terminated 200 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 0 + ,.headers={} + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_KA_204 16 +, {.name= "HTTP/1.1 with a 204 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No content\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.num_headers= 0 + ,.headers={} + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_NOKA_204 17 +, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No content\r\n" + "Connection: close\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.num_headers= 1 + ,.headers= + { { "Connection", "close" } + } + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_KA_CHUNKED_200 18 +, {.name= "HTTP/1.1 with chunked endocing and a 200 response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body_size= 0 + ,.body= "" + } + +#if !HTTP_PARSER_STRICT +#define SPACE_IN_FIELD_RES 19 +/* Should handle spaces in header fields */ +, {.name= "field space" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Server: Microsoft-IIS/6.0\r\n" + "X-Powered-By: ASP.NET\r\n" + "en-US Content-Type: text/xml\r\n" /* this is the problem */ + "Content-Type: text/xml\r\n" + "Content-Length: 16\r\n" + "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "hello" /* fake body */ + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 7 + ,.headers= + { { "Server", "Microsoft-IIS/6.0" } + , { "X-Powered-By", "ASP.NET" } + , { "en-US Content-Type", "text/xml" } + , { "Content-Type", "text/xml" } + , { "Content-Length", "16" } + , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" } + , { "Connection", "keep-alive" } + } + ,.body= "hello" + } +#endif /* !HTTP_PARSER_STRICT */ + +, {.name= NULL } /* sentinel */ +}; + +/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so + * define it ourselves. + */ +size_t +strnlen(const char *s, size_t maxlen) +{ + const char *p; + + p = memchr(s, '\0', maxlen); + if (p == NULL) + return maxlen; + + return p - s; +} + +size_t +strlncat(char *dst, size_t len, const char *src, size_t n) +{ + size_t slen; + size_t dlen; + size_t rlen; + size_t ncpy; + + slen = strnlen(src, n); + dlen = strnlen(dst, len); + + if (dlen < len) { + rlen = len - dlen; + ncpy = slen < rlen ? slen : (rlen - 1); + memcpy(dst + dlen, src, ncpy); + dst[dlen + ncpy] = '\0'; + } + + assert(len > slen + dlen); + return slen + dlen; +} + +size_t +strlcat(char *dst, const char *src, size_t len) +{ + return strlncat(dst, len, src, (size_t) -1); +} + +size_t +strlncpy(char *dst, size_t len, const char *src, size_t n) +{ + size_t slen; + size_t ncpy; + + slen = strnlen(src, n); + + if (len > 0) { + ncpy = slen < len ? slen : (len - 1); + memcpy(dst, src, ncpy); + dst[ncpy] = '\0'; + } + + assert(len > slen); + return slen; +} + +size_t +strlcpy(char *dst, const char *src, size_t len) +{ + return strlncpy(dst, len, src, (size_t) -1); +} + +int +request_url_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + strlncat(messages[num_messages].request_url, + sizeof(messages[num_messages].request_url), + buf, + len); + return 0; +} + +int +status_complete_cb (http_parser *p) { + assert(p == parser); + p->data++; + return 0; +} + +int +header_field_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + struct message *m = &messages[num_messages]; + + if (m->last_header_element != FIELD) + m->num_headers++; + + strlncat(m->headers[m->num_headers-1][0], + sizeof(m->headers[m->num_headers-1][0]), + buf, + len); + + m->last_header_element = FIELD; + + return 0; +} + +int +header_value_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + struct message *m = &messages[num_messages]; + + strlncat(m->headers[m->num_headers-1][1], + sizeof(m->headers[m->num_headers-1][1]), + buf, + len); + + m->last_header_element = VALUE; + + return 0; +} + +void +check_body_is_final (const http_parser *p) +{ + if (messages[num_messages].body_is_final) { + fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 " + "on last on_body callback call " + "but it doesn't! ***\n\n"); + assert(0); + abort(); + } + messages[num_messages].body_is_final = http_body_is_final(p); +} + +int +body_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + strlncat(messages[num_messages].body, + sizeof(messages[num_messages].body), + buf, + len); + messages[num_messages].body_size += len; + check_body_is_final(p); + // printf("body_cb: '%s'\n", requests[num_messages].body); + return 0; +} + +int +count_body_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + assert(buf); + messages[num_messages].body_size += len; + check_body_is_final(p); + return 0; +} + +int +message_begin_cb (http_parser *p) +{ + assert(p == parser); + messages[num_messages].message_begin_cb_called = TRUE; + return 0; +} + +int +headers_complete_cb (http_parser *p) +{ + assert(p == parser); + messages[num_messages].method = parser->method; + messages[num_messages].status_code = parser->status_code; + messages[num_messages].http_major = parser->http_major; + messages[num_messages].http_minor = parser->http_minor; + messages[num_messages].headers_complete_cb_called = TRUE; + messages[num_messages].should_keep_alive = http_should_keep_alive(parser); + return 0; +} + +int +message_complete_cb (http_parser *p) +{ + assert(p == parser); + if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser)) + { + fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same " + "value in both on_message_complete and on_headers_complete " + "but it doesn't! ***\n\n"); + assert(0); + abort(); + } + + if (messages[num_messages].body_size && + http_body_is_final(p) && + !messages[num_messages].body_is_final) + { + fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 " + "on last on_body callback call " + "but it doesn't! ***\n\n"); + assert(0); + abort(); + } + + messages[num_messages].message_complete_cb_called = TRUE; + + messages[num_messages].message_complete_on_eof = currently_parsing_eof; + + num_messages++; + return 0; +} + +/* These dontcall_* callbacks exist so that we can verify that when we're + * paused, no additional callbacks are invoked */ +int +dontcall_message_begin_cb (http_parser *p) +{ + if (p) { } // gcc + fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n"); + abort(); +} + +int +dontcall_header_field_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n"); + abort(); +} + +int +dontcall_header_value_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n"); + abort(); +} + +int +dontcall_request_url_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n"); + abort(); +} + +int +dontcall_body_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n"); + abort(); +} + +int +dontcall_headers_complete_cb (http_parser *p) +{ + if (p) { } // gcc + fprintf(stderr, "\n\n*** on_headers_complete() called on paused " + "parser ***\n\n"); + abort(); +} + +int +dontcall_message_complete_cb (http_parser *p) +{ + if (p) { } // gcc + fprintf(stderr, "\n\n*** on_message_complete() called on paused " + "parser ***\n\n"); + abort(); +} + +static http_parser_settings settings_dontcall = + {.on_message_begin = dontcall_message_begin_cb + ,.on_header_field = dontcall_header_field_cb + ,.on_header_value = dontcall_header_value_cb + ,.on_url = dontcall_request_url_cb + ,.on_body = dontcall_body_cb + ,.on_headers_complete = dontcall_headers_complete_cb + ,.on_message_complete = dontcall_message_complete_cb + }; + +/* These pause_* callbacks always pause the parser and just invoke the regular + * callback that tracks content. Before returning, we overwrite the parser + * settings to point to the _dontcall variety so that we can verify that + * the pause actually did, you know, pause. */ +int +pause_message_begin_cb (http_parser *p) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return message_begin_cb(p); +} + +int +pause_header_field_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return header_field_cb(p, buf, len); +} + +int +pause_header_value_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return header_value_cb(p, buf, len); +} + +int +pause_request_url_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return request_url_cb(p, buf, len); +} + +int +pause_body_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return body_cb(p, buf, len); +} + +int +pause_headers_complete_cb (http_parser *p) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return headers_complete_cb(p); +} + +int +pause_message_complete_cb (http_parser *p) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return message_complete_cb(p); +} + +static http_parser_settings settings_pause = + {.on_message_begin = pause_message_begin_cb + ,.on_header_field = pause_header_field_cb + ,.on_header_value = pause_header_value_cb + ,.on_url = pause_request_url_cb + ,.on_body = pause_body_cb + ,.on_headers_complete = pause_headers_complete_cb + ,.on_message_complete = pause_message_complete_cb + }; + +static http_parser_settings settings = + {.on_message_begin = message_begin_cb + ,.on_header_field = header_field_cb + ,.on_header_value = header_value_cb + ,.on_url = request_url_cb + ,.on_body = body_cb + ,.on_headers_complete = headers_complete_cb + ,.on_message_complete = message_complete_cb + }; + +static http_parser_settings settings_count_body = + {.on_message_begin = message_begin_cb + ,.on_header_field = header_field_cb + ,.on_header_value = header_value_cb + ,.on_url = request_url_cb + ,.on_body = count_body_cb + ,.on_headers_complete = headers_complete_cb + ,.on_message_complete = message_complete_cb + }; + +static http_parser_settings settings_null = + {.on_message_begin = 0 + ,.on_header_field = 0 + ,.on_header_value = 0 + ,.on_url = 0 + ,.on_body = 0 + ,.on_headers_complete = 0 + ,.on_message_complete = 0 + }; + +void +parser_init (enum http_parser_type type) +{ + num_messages = 0; + + assert(parser == NULL); + + parser = malloc(sizeof(http_parser)); + + http_parser_init(parser, type); + + memset(&messages, 0, sizeof messages); + +} + +void +parser_free () +{ + assert(parser); + free(parser); + parser = NULL; +} + +size_t parse (const char *buf, size_t len) +{ + size_t nparsed; + currently_parsing_eof = (len == 0); + nparsed = http_parser_execute(parser, &settings, buf, len); + return nparsed; +} + +size_t parse_count_body (const char *buf, size_t len) +{ + size_t nparsed; + currently_parsing_eof = (len == 0); + nparsed = http_parser_execute(parser, &settings_count_body, buf, len); + return nparsed; +} + +size_t parse_pause (const char *buf, size_t len) +{ + size_t nparsed; + http_parser_settings s = settings_pause; + + currently_parsing_eof = (len == 0); + current_pause_parser = &s; + nparsed = http_parser_execute(parser, current_pause_parser, buf, len); + return nparsed; +} + +static inline int +check_str_eq (const struct message *m, + const char *prop, + const char *expected, + const char *found) { + if ((expected == NULL) != (found == NULL)) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %s\n", (expected == NULL) ? "NULL" : expected); + printf(" found %s\n", (found == NULL) ? "NULL" : found); + return 0; + } + if (expected != NULL && 0 != strcmp(expected, found)) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected '%s'\n", expected); + printf(" found '%s'\n", found); + return 0; + } + return 1; +} + +static inline int +check_num_eq (const struct message *m, + const char *prop, + int expected, + int found) { + if (expected != found) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %d\n", expected); + printf(" found %d\n", found); + return 0; + } + return 1; +} + +#define MESSAGE_CHECK_STR_EQ(expected, found, prop) \ + if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \ + if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \ +do { \ + char ubuf[256]; \ + \ + if ((u)->field_set & (1 << (fn))) { \ + memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \ + (u)->field_data[(fn)].len); \ + ubuf[(u)->field_data[(fn)].len] = '\0'; \ + } else { \ + ubuf[0] = '\0'; \ + } \ + \ + check_str_eq(expected, #prop, expected->prop, ubuf); \ +} while(0) + +int +message_eq (int index, const struct message *expected) +{ + int i; + struct message *m = &messages[index]; + + MESSAGE_CHECK_NUM_EQ(expected, m, http_major); + MESSAGE_CHECK_NUM_EQ(expected, m, http_minor); + + if (expected->type == HTTP_REQUEST) { + MESSAGE_CHECK_NUM_EQ(expected, m, method); + } else { + MESSAGE_CHECK_NUM_EQ(expected, m, status_code); + } + + MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); + MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); + + assert(m->message_begin_cb_called); + assert(m->headers_complete_cb_called); + assert(m->message_complete_cb_called); + + + MESSAGE_CHECK_STR_EQ(expected, m, request_url); + + /* Check URL components; we can't do this w/ CONNECT since it doesn't + * send us a well-formed URL. + */ + if (*m->request_url && m->method != HTTP_CONNECT) { + struct http_parser_url u; + + if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) { + fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n", + m->request_url); + abort(); + } + + if (expected->host) { + MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST); + } + + if (expected->userinfo) { + MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO); + } + + m->port = (u.field_set & (1 << UF_PORT)) ? + u.port : 0; + + MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY); + MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT); + MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH); + MESSAGE_CHECK_NUM_EQ(expected, m, port); + } + + if (expected->body_size) { + MESSAGE_CHECK_NUM_EQ(expected, m, body_size); + } else { + MESSAGE_CHECK_STR_EQ(expected, m, body); + } + + MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); + + int r; + for (i = 0; i < m->num_headers; i++) { + r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]); + if (!r) return 0; + r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]); + if (!r) return 0; + } + + MESSAGE_CHECK_STR_EQ(expected, m, upgrade); + + return 1; +} + +/* Given a sequence of varargs messages, return the number of them that the + * parser should successfully parse, taking into account that upgraded + * messages prevent all subsequent messages from being parsed. + */ +size_t +count_parsed_messages(const size_t nmsgs, ...) { + size_t i; + va_list ap; + + va_start(ap, nmsgs); + + for (i = 0; i < nmsgs; i++) { + struct message *m = va_arg(ap, struct message *); + + if (m->upgrade) { + va_end(ap); + return i + 1; + } + } + + va_end(ap); + return nmsgs; +} + +/* Given a sequence of bytes and the number of these that we were able to + * parse, verify that upgrade bodies are correct. + */ +void +upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) { + va_list ap; + size_t i; + size_t off = 0; + + va_start(ap, nmsgs); + + for (i = 0; i < nmsgs; i++) { + struct message *m = va_arg(ap, struct message *); + + off += strlen(m->raw); + + if (m->upgrade) { + off -= strlen(m->upgrade); + + /* Check the portion of the response after its specified upgrade */ + if (!check_str_eq(m, "upgrade", body + off, body + nread)) { + abort(); + } + + /* Fix up the response so that message_eq() will verify the beginning + * of the upgrade */ + *(body + nread + strlen(m->upgrade)) = '\0'; + messages[num_messages -1 ].upgrade = body + nread; + + va_end(ap); + return; + } + } + + va_end(ap); + printf("\n\n*** Error: expected a message with upgrade ***\n"); + + abort(); +} + +static void +print_error (const char *raw, size_t error_location) +{ + fprintf(stderr, "\n*** %s ***\n\n", + http_errno_description(HTTP_PARSER_ERRNO(parser))); + + int this_line = 0, char_len = 0; + size_t i, j, len = strlen(raw), error_location_line = 0; + for (i = 0; i < len; i++) { + if (i == error_location) this_line = 1; + switch (raw[i]) { + case '\r': + char_len = 2; + fprintf(stderr, "\\r"); + break; + + case '\n': + char_len = 2; + fprintf(stderr, "\\n\n"); + + if (this_line) goto print; + + error_location_line = 0; + continue; + + default: + char_len = 1; + fputc(raw[i], stderr); + break; + } + if (!this_line) error_location_line += char_len; + } + + fprintf(stderr, "[eof]\n"); + + print: + for (j = 0; j < error_location_line; j++) { + fputc(' ', stderr); + } + fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location); +} + +void +test_preserve_data (void) +{ + char my_data[] = "application-specific data"; + http_parser parser; + parser.data = my_data; + http_parser_init(&parser, HTTP_REQUEST); + if (parser.data != my_data) { + printf("\n*** parser.data not preserved accross http_parser_init ***\n\n"); + abort(); + } +} + +struct url_test { + const char *name; + const char *url; + int is_connect; + struct http_parser_url u; + int rv; +}; + +const struct url_test url_tests[] = +{ {.name="proxy request" + ,.url="http://hostname/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 7, 8 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 15, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="proxy request with port" + ,.url="http://hostname:444/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) + ,.port=444 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 7, 8 } /* UF_HOST */ + ,{ 16, 3 } /* UF_PORT */ + ,{ 19, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="CONNECT request" + ,.url="hostname:443" + ,.is_connect=1 + ,.u= + {.field_set=(1 << UF_HOST) | (1 << UF_PORT) + ,.port=443 + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 0, 8 } /* UF_HOST */ + ,{ 9, 3 } /* UF_PORT */ + ,{ 0, 0 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="CONNECT request but not connect" + ,.url="hostname:443" + ,.is_connect=0 + ,.rv=1 + } + +, {.name="proxy ipv6 request" + ,.url="http://[1:2::3:4]/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 8 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 17, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="proxy ipv6 request with port" + ,.url="http://[1:2::3:4]:67/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) + ,.port=67 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 8 } /* UF_HOST */ + ,{ 18, 2 } /* UF_PORT */ + ,{ 20, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="CONNECT ipv6 address" + ,.url="[1:2::3:4]:443" + ,.is_connect=1 + ,.u= + {.field_set=(1 << UF_HOST) | (1 << UF_PORT) + ,.port=443 + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 1, 8 } /* UF_HOST */ + ,{ 11, 3 } /* UF_PORT */ + ,{ 0, 0 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="ipv4 in ipv6 address" + ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 37 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 46, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="extra ? in query string" + ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css," + "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css," + "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css" + ,.is_connect=0 + ,.u= + {.field_set=(1<field_set, u->port); + for (i = 0; i < UF_MAX; i++) { + if ((u->field_set & (1 << i)) == 0) { + printf("\tfield_data[%u]: unset\n", i); + continue; + } + + printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"", + i, + u->field_data[i].off, + u->field_data[i].len, + u->field_data[i].len, + url + u->field_data[i].off); + } +} + +void +test_parse_url (void) +{ + struct http_parser_url u; + const struct url_test *test; + unsigned int i; + int rv; + + for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) { + test = &url_tests[i]; + memset(&u, 0, sizeof(u)); + + rv = http_parser_parse_url(test->url, + strlen(test->url), + test->is_connect, + &u); + + if (test->rv == 0) { + if (rv != 0) { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " + "unexpected rv %d ***\n\n", test->url, test->name, rv); + abort(); + } + + if (memcmp(&u, &test->u, sizeof(u)) != 0) { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n", + test->url, test->name); + + printf("target http_parser_url:\n"); + dump_url(test->url, &test->u); + printf("result http_parser_url:\n"); + dump_url(test->url, &u); + + abort(); + } + } else { + /* test->rv != 0 */ + if (rv == 0) { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " + "unexpected rv %d ***\n\n", test->url, test->name, rv); + abort(); + } + } + } +} + +void +test_method_str (void) +{ + assert(0 == strcmp("GET", http_method_str(HTTP_GET))); + assert(0 == strcmp("", http_method_str(1337))); +} + +void +test_message (const struct message *message) +{ + size_t raw_len = strlen(message->raw); + size_t msg1len; + for (msg1len = 0; msg1len < raw_len; msg1len++) { + parser_init(message->type); + + size_t read; + const char *msg1 = message->raw; + const char *msg2 = msg1 + msg1len; + size_t msg2len = raw_len - msg1len; + + if (msg1len) { + read = parse(msg1, msg1len); + + if (message->upgrade && parser->upgrade) { + messages[num_messages - 1].upgrade = msg1 + read; + goto test; + } + + if (read != msg1len) { + print_error(msg1, read); + abort(); + } + } + + + read = parse(msg2, msg2len); + + if (message->upgrade && parser->upgrade) { + messages[num_messages - 1].upgrade = msg2 + read; + goto test; + } + + if (read != msg2len) { + print_error(msg2, read); + abort(); + } + + read = parse(NULL, 0); + + if (read != 0) { + print_error(message->raw, read); + abort(); + } + + test: + + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + abort(); + } + + if(!message_eq(0, message)) abort(); + + parser_free(); + } +} + +void +test_message_count_body (const struct message *message) +{ + parser_init(message->type); + + size_t read; + size_t l = strlen(message->raw); + size_t i, toread; + size_t chunk = 4024; + + for (i = 0; i < l; i+= chunk) { + toread = MIN(l-i, chunk); + read = parse_count_body(message->raw + i, toread); + if (read != toread) { + print_error(message->raw, read); + abort(); + } + } + + + read = parse_count_body(NULL, 0); + if (read != 0) { + print_error(message->raw, read); + abort(); + } + + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + abort(); + } + + if(!message_eq(0, message)) abort(); + + parser_free(); +} + +void +test_simple (const char *buf, enum http_errno err_expected) +{ + parser_init(HTTP_REQUEST); + + size_t parsed; + int pass; + enum http_errno err; + + parsed = parse(buf, strlen(buf)); + pass = (parsed == strlen(buf)); + err = HTTP_PARSER_ERRNO(parser); + parsed = parse(NULL, 0); + pass &= (parsed == 0); + + parser_free(); + + /* In strict mode, allow us to pass with an unexpected HPE_STRICT as + * long as the caller isn't expecting success. + */ +#if HTTP_PARSER_STRICT + if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) { +#else + if (err_expected != err) { +#endif + fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n", + http_errno_name(err_expected), http_errno_name(err), buf); + abort(); + } +} + +void +test_header_overflow_error (int req) +{ + http_parser parser; + http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE); + size_t parsed; + const char *buf; + buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n"; + parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf)); + assert(parsed == strlen(buf)); + + buf = "header-key: header-value\r\n"; + size_t buflen = strlen(buf); + + int i; + for (i = 0; i < 10000; i++) { + parsed = http_parser_execute(&parser, &settings_null, buf, buflen); + if (parsed != buflen) { + //fprintf(stderr, "error found on iter %d\n", i); + assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW); + return; + } + } + + fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n"); + abort(); +} + +static void +test_content_length_overflow (const char *buf, size_t buflen, int expect_ok) +{ + http_parser parser; + http_parser_init(&parser, HTTP_RESPONSE); + http_parser_execute(&parser, &settings_null, buf, buflen); + + if (expect_ok) + assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK); + else + assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH); +} + +void +test_header_content_length_overflow_error (void) +{ +#define X(size) \ + "HTTP/1.1 200 OK\r\n" \ + "Content-Length: " #size "\r\n" \ + "\r\n" + const char a[] = X(18446744073709551614); /* 2^64-2 */ + const char b[] = X(18446744073709551615); /* 2^64-1 */ + const char c[] = X(18446744073709551616); /* 2^64 */ +#undef X + test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */ + test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */ + test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */ +} + +void +test_chunk_content_length_overflow_error (void) +{ +#define X(size) \ + "HTTP/1.1 200 OK\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "\r\n" \ + #size "\r\n" \ + "..." + const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */ + const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */ + const char c[] = X(10000000000000000); /* 2^64 */ +#undef X + test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */ + test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */ + test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */ +} + +void +test_no_overflow_long_body (int req, size_t length) +{ + http_parser parser; + http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE); + size_t parsed; + size_t i; + char buf1[3000]; + size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n", + req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length); + parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len); + if (parsed != buf1len) + goto err; + + for (i = 0; i < length; i++) { + char foo = 'a'; + parsed = http_parser_execute(&parser, &settings_null, &foo, 1); + if (parsed != 1) + goto err; + } + + parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len); + if (parsed != buf1len) goto err; + return; + + err: + fprintf(stderr, + "\n*** error in test_no_overflow_long_body %s of length %lu ***\n", + req ? "REQUEST" : "RESPONSE", + (unsigned long)length); + abort(); +} + +void +test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3) +{ + int message_count = count_parsed_messages(3, r1, r2, r3); + + char total[ strlen(r1->raw) + + strlen(r2->raw) + + strlen(r3->raw) + + 1 + ]; + total[0] = '\0'; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + parser_init(r1->type); + + size_t read; + + read = parse(total, strlen(total)); + + if (parser->upgrade) { + upgrade_message_fix(total, read, 3, r1, r2, r3); + goto test; + } + + if (read != strlen(total)) { + print_error(total, read); + abort(); + } + + read = parse(NULL, 0); + + if (read != 0) { + print_error(total, read); + abort(); + } + +test: + + if (message_count != num_messages) { + fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages); + abort(); + } + + if (!message_eq(0, r1)) abort(); + if (message_count > 1 && !message_eq(1, r2)) abort(); + if (message_count > 2 && !message_eq(2, r3)) abort(); + + parser_free(); +} + +/* SCAN through every possible breaking to make sure the + * parser can handle getting the content in any chunks that + * might come from the socket + */ +void +test_scan (const struct message *r1, const struct message *r2, const struct message *r3) +{ + char total[80*1024] = "\0"; + char buf1[80*1024] = "\0"; + char buf2[80*1024] = "\0"; + char buf3[80*1024] = "\0"; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + size_t read; + + int total_len = strlen(total); + + int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2; + int ops = 0 ; + + size_t buf1_len, buf2_len, buf3_len; + int message_count = count_parsed_messages(3, r1, r2, r3); + + int i,j,type_both; + for (type_both = 0; type_both < 2; type_both ++ ) { + for (j = 2; j < total_len; j ++ ) { + for (i = 1; i < j; i ++ ) { + + if (ops % 1000 == 0) { + printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops); + fflush(stdout); + } + ops += 1; + + parser_init(type_both ? HTTP_BOTH : r1->type); + + buf1_len = i; + strlncpy(buf1, sizeof(buf1), total, buf1_len); + buf1[buf1_len] = 0; + + buf2_len = j - i; + strlncpy(buf2, sizeof(buf1), total+i, buf2_len); + buf2[buf2_len] = 0; + + buf3_len = total_len - j; + strlncpy(buf3, sizeof(buf1), total+j, buf3_len); + buf3[buf3_len] = 0; + + read = parse(buf1, buf1_len); + + if (parser->upgrade) goto test; + + if (read != buf1_len) { + print_error(buf1, read); + goto error; + } + + read += parse(buf2, buf2_len); + + if (parser->upgrade) goto test; + + if (read != buf1_len + buf2_len) { + print_error(buf2, read); + goto error; + } + + read += parse(buf3, buf3_len); + + if (parser->upgrade) goto test; + + if (read != buf1_len + buf2_len + buf3_len) { + print_error(buf3, read); + goto error; + } + + parse(NULL, 0); + +test: + if (parser->upgrade) { + upgrade_message_fix(total, read, 3, r1, r2, r3); + } + + if (message_count != num_messages) { + fprintf(stderr, "\n\nParser didn't see %d messages only %d\n", + message_count, num_messages); + goto error; + } + + if (!message_eq(0, r1)) { + fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); + goto error; + } + + if (message_count > 1 && !message_eq(1, r2)) { + fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); + goto error; + } + + if (message_count > 2 && !message_eq(2, r3)) { + fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); + goto error; + } + + parser_free(); + } + } + } + puts("\b\b\b\b100%"); + return; + + error: + fprintf(stderr, "i=%d j=%d\n", i, j); + fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1); + fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2); + fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3); + abort(); +} + +// user required to free the result +// string terminated by \0 +char * +create_large_chunked_message (int body_size_in_kb, const char* headers) +{ + int i; + size_t wrote = 0; + size_t headers_len = strlen(headers); + size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6; + char * buf = malloc(bufsize); + + memcpy(buf, headers, headers_len); + wrote += headers_len; + + for (i = 0; i < body_size_in_kb; i++) { + // write 1kb chunk into the body. + memcpy(buf + wrote, "400\r\n", 5); + wrote += 5; + memset(buf + wrote, 'C', 1024); + wrote += 1024; + strcpy(buf + wrote, "\r\n"); + wrote += 2; + } + + memcpy(buf + wrote, "0\r\n\r\n", 6); + wrote += 6; + assert(wrote == bufsize); + + return buf; +} + +void +test_status_complete (void) +{ + parser_init(HTTP_RESPONSE); + parser->data = 0; + http_parser_settings settings = settings_null; + settings.on_status_complete = status_complete_cb; + + char *response = "don't mind me, just a simple response"; + http_parser_execute(parser, &settings, response, strlen(response)); + assert(parser->data == (void*)0); // the status_complete callback was never called + assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line +} + +/* Verify that we can pause parsing at any of the bytes in the + * message and still get the result that we're expecting. */ +void +test_message_pause (const struct message *msg) +{ + char *buf = (char*) msg->raw; + size_t buflen = strlen(msg->raw); + size_t nread; + + parser_init(msg->type); + + do { + nread = parse_pause(buf, buflen); + + // We can only set the upgrade buffer once we've gotten our message + // completion callback. + if (messages[0].message_complete_cb_called && + msg->upgrade && + parser->upgrade) { + messages[0].upgrade = buf + nread; + goto test; + } + + if (nread < buflen) { + + // Not much do to if we failed a strict-mode check + if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) { + parser_free(); + return; + } + + assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED); + } + + buf += nread; + buflen -= nread; + http_parser_pause(parser, 0); + } while (buflen > 0); + + nread = parse_pause(NULL, 0); + assert (nread == 0); + +test: + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name); + abort(); + } + + if(!message_eq(0, msg)) abort(); + + parser_free(); +} + +int +main (void) +{ + parser = NULL; + int i, j, k; + int request_count; + int response_count; + + printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser)); + + for (request_count = 0; requests[request_count].name; request_count++); + for (response_count = 0; responses[response_count].name; response_count++); + + //// API + test_preserve_data(); + test_parse_url(); + test_method_str(); + + //// OVERFLOW CONDITIONS + + test_header_overflow_error(HTTP_REQUEST); + test_no_overflow_long_body(HTTP_REQUEST, 1000); + test_no_overflow_long_body(HTTP_REQUEST, 100000); + + test_header_overflow_error(HTTP_RESPONSE); + test_no_overflow_long_body(HTTP_RESPONSE, 1000); + test_no_overflow_long_body(HTTP_RESPONSE, 100000); + + test_header_content_length_overflow_error(); + test_chunk_content_length_overflow_error(); + + //// RESPONSES + + for (i = 0; i < response_count; i++) { + test_message(&responses[i]); + } + + for (i = 0; i < response_count; i++) { + test_message_pause(&responses[i]); + } + + for (i = 0; i < response_count; i++) { + if (!responses[i].should_keep_alive) continue; + for (j = 0; j < response_count; j++) { + if (!responses[j].should_keep_alive) continue; + for (k = 0; k < response_count; k++) { + test_multiple3(&responses[i], &responses[j], &responses[k]); + } + } + } + + test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]); + test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]); + + // test very large chunked response + { + char * msg = create_large_chunked_message(31337, + "HTTP/1.0 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/plain\r\n" + "\r\n"); + struct message large_chunked = + {.name= "large chunked" + ,.type= HTTP_RESPONSE + ,.raw= msg + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Content-Type", "text/plain" } + } + ,.body_size= 31337*1024 + }; + test_message_count_body(&large_chunked); + free(msg); + } + + + + printf("response scan 1/2 "); + test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY] + , &responses[NO_BODY_HTTP10_KA_204] + , &responses[NO_REASON_PHRASE] + ); + + printf("response scan 2/2 "); + test_scan( &responses[BONJOUR_MADAME_FR] + , &responses[UNDERSTORE_HEADER_KEY] + , &responses[NO_CARRIAGE_RET] + ); + + puts("responses okay"); + + + /// REQUESTS + + test_simple("hello world", HPE_INVALID_METHOD); + test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION); + + + test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD); + test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD); + test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD); + + // Well-formed but incomplete + test_simple("GET / HTTP/1.1\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 6\r\n" + "\r\n" + "fooba", + HPE_OK); + + static const char *all_methods[] = { + "DELETE", + "GET", + "HEAD", + "POST", + "PUT", + //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel + "OPTIONS", + "TRACE", + "COPY", + "LOCK", + "MKCOL", + "MOVE", + "PROPFIND", + "PROPPATCH", + "UNLOCK", + "REPORT", + "MKACTIVITY", + "CHECKOUT", + "MERGE", + "M-SEARCH", + "NOTIFY", + "SUBSCRIBE", + "UNSUBSCRIBE", + "PATCH", + 0 }; + const char **this_method; + for (this_method = all_methods; *this_method; this_method++) { + char buf[200]; + sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); + test_simple(buf, HPE_OK); + } + + static const char *bad_methods[] = { + "C******", + "M****", + 0 }; + for (this_method = bad_methods; *this_method; this_method++) { + char buf[200]; + sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); + test_simple(buf, HPE_UNKNOWN); + } + + const char *dumbfuck2 = + "GET / HTTP/1.1\r\n" + "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n" + "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n" + "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n" + "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n" + "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n" + "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n" + "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n" + "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n" + "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n" + "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n" + "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n" + "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n" + "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n" + "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n" + "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n" + "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n" + "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n" + "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n" + "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n" + "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n" + "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n" + "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n" + "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n" + "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n" + "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n" + "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n" + "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n" + "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n" + "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n" + "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n" + "\tRA==\r\n" + "\t-----END CERTIFICATE-----\r\n" + "\r\n"; + test_simple(dumbfuck2, HPE_OK); + +#if 0 + // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body + // until EOF. + // + // no content-length + // error if there is a body without content length + const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + "HELLO"; + test_simple(bad_get_no_headers_no_body, 0); +#endif + /* TODO sending junk and large headers gets rejected */ + + + /* check to make sure our predefined requests are okay */ + for (i = 0; requests[i].name; i++) { + test_message(&requests[i]); + } + + for (i = 0; i < request_count; i++) { + test_message_pause(&requests[i]); + } + + for (i = 0; i < request_count; i++) { + if (!requests[i].should_keep_alive) continue; + for (j = 0; j < request_count; j++) { + if (!requests[j].should_keep_alive) continue; + for (k = 0; k < request_count; k++) { + test_multiple3(&requests[i], &requests[j], &requests[k]); + } + } + } + + printf("request scan 1/4 "); + test_scan( &requests[GET_NO_HEADERS_NO_BODY] + , &requests[GET_ONE_HEADER_NO_BODY] + , &requests[GET_NO_HEADERS_NO_BODY] + ); + + printf("request scan 2/4 "); + test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE] + , &requests[POST_IDENTITY_BODY_WORLD] + , &requests[GET_FUNKY_CONTENT_LENGTH] + ); + + printf("request scan 3/4 "); + test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END] + , &requests[CHUNKED_W_TRAILING_HEADERS] + , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH] + ); + + printf("request scan 4/4 "); + test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET] + , &requests[PREFIX_NEWLINE_GET ] + , &requests[CONNECT_REQUEST] + ); + + test_status_complete(); + + puts("requests okay"); + + return 0; +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped new file mode 100644 index 0000000..038bb52 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped @@ -0,0 +1,845 @@ +name :curl get +raw :"GET /test HTTP/1.1\r\nUser-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\nHost: 0.0.0.0=5000\r\nAccept: */*\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/test +request_url :/test +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "User-Agent": "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1"} +header_1 :{ "Host": "0.0.0.0=5000"} +header_2 :{ "Accept": "*/*"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :firefox get +raw :"GET /favicon.ico HTTP/1.1\r\nHost: 0.0.0.0=5000\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/favicon.ico +request_url :/favicon.ico +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Host": "0.0.0.0=5000"} +header_1 :{ "User-Agent": "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0"} +header_2 :{ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"} +header_3 :{ "Accept-Language": "en-us,en;q=0.5"} +header_4 :{ "Accept-Encoding": "gzip,deflate"} +header_5 :{ "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7"} +header_6 :{ "Keep-Alive": "300"} +header_7 :{ "Connection": "keep-alive"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :dumbfuck +raw :"GET /dumbfuck HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/dumbfuck +request_url :/dumbfuck +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "aaaaaaaaaaaaa": "++++++++++"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :fragment in url +raw :"GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/forums/1/topics/2375 +request_url :/forums/1/topics/2375?page=1#posts-17408 +fragment :posts-17408 +query_string:page=1 +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :get no headers no body +raw :"GET /get_no_headers_no_body/world HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/get_no_headers_no_body/world +request_url :/get_no_headers_no_body/world +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :get one header no body +raw :"GET /get_one_header_no_body HTTP/1.1\r\nAccept: */*\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/get_one_header_no_body +request_url :/get_one_header_no_body +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Accept": "*/*"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :get funky content length body hello +raw :"GET /get_funky_content_length_body_hello HTTP/1.0\r\nconTENT-Length: 5\r\n\r\nHELLO" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/get_funky_content_length_body_hello +request_url :/get_funky_content_length_body_hello +fragment : +query_string: +body :"HELLO" +body_size :0 +header_0 :{ "conTENT-Length": "5"} +should_keep_alive :0 +http_major :1 +http_minor :0 + +name :post identity body world +raw :"POST /post_identity_body_world?q=search#hey HTTP/1.1\r\nAccept: */*\r\nTransfer-Encoding: identity\r\nContent-Length: 5\r\n\r\nWorld" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/post_identity_body_world +request_url :/post_identity_body_world?q=search#hey +fragment :hey +query_string:q=search +body :"World" +body_size :0 +header_0 :{ "Accept": "*/*"} +header_1 :{ "Transfer-Encoding": "identity"} +header_2 :{ "Content-Length": "5"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :post - chunked body: all your base are belong to us +raw :"POST /post_chunked_all_your_base HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1e\r\nall your base are belong to us\r\n0\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/post_chunked_all_your_base +request_url :/post_chunked_all_your_base +fragment : +query_string: +body :"all your base are belong to us" +body_size :0 +header_0 :{ "Transfer-Encoding": "chunked"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :two chunks ; triple zero ending +raw :"POST /two_chunks_mult_zero_end HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n000\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/two_chunks_mult_zero_end +request_url :/two_chunks_mult_zero_end +fragment : +query_string: +body :"hello world" +body_size :0 +header_0 :{ "Transfer-Encoding": "chunked"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :chunked with trailing headers. blech. +raw :"POST /chunked_w_trailing_headers HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n0\r\nVary: *\r\nContent-Type: text/plain\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/chunked_w_trailing_headers +request_url :/chunked_w_trailing_headers +fragment : +query_string: +body :"hello world" +body_size :0 +header_0 :{ "Transfer-Encoding": "chunked"} +header_1 :{ "Vary": "*"} +header_2 :{ "Content-Type": "text/plain"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :with bullshit after the length +raw :"POST /chunked_w_bullshit_after_length HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n6; blahblah; blah\r\n world\r\n0\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/chunked_w_bullshit_after_length +request_url :/chunked_w_bullshit_after_length +fragment : +query_string: +body :"hello world" +body_size :0 +header_0 :{ "Transfer-Encoding": "chunked"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :with quotes +raw :"GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/with_"stupid"_quotes +request_url :/with_"stupid"_quotes?foo="bar" +fragment : +query_string:foo="bar" +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :apachebench get +raw :"GET /test HTTP/1.0\r\nHost: 0.0.0.0:5000\r\nUser-Agent: ApacheBench/2.3\r\nAccept: */*\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/test +request_url :/test +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Host": "0.0.0.0:5000"} +header_1 :{ "User-Agent": "ApacheBench/2.3"} +header_2 :{ "Accept": "*/*"} +should_keep_alive :0 +http_major :1 +http_minor :0 + +name :query url with question mark +raw :"GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/test.cgi +request_url :/test.cgi?foo=bar?baz +fragment : +query_string:foo=bar?baz +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :newline prefix get +raw :"\r\nGET /test HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/test +request_url :/test +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :upgrade request +raw :"GET /demo HTTP/1.1\r\nHost: example.com\r\nConnection: Upgrade\r\nSec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\nSec-WebSocket-Protocol: sample\r\nUpgrade: WebSocket\r\nSec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\nOrigin: http://example.com\r\n\r\nHot diggity dogg" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/demo +request_url :/demo +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Host": "example.com"} +header_1 :{ "Connection": "Upgrade"} +header_2 :{ "Sec-WebSocket-Key2": "12998 5 Y3 1 .P00"} +header_3 :{ "Sec-WebSocket-Protocol": "sample"} +header_4 :{ "Upgrade": "WebSocket"} +header_5 :{ "Sec-WebSocket-Key1": "4 @1 46546xW%0l 1 5"} +header_6 :{ "Origin": "http://example.com"} +should_keep_alive :1 +upgrade :"Hot diggity dogg" +http_major :1 +http_minor :1 + +name :connect request +raw :"CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\nUser-agent: Mozilla/1.1N\r\nProxy-authorization: basic aGVsbG86d29ybGQ=\r\n\r\nsome data\r\nand yet even more data" +type :HTTP_REQUEST +method: HTTP_CONNECT +status_code :0 +request_path: +request_url :0-home0.netscape.com:443 +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "User-agent": "Mozilla/1.1N"} +header_1 :{ "Proxy-authorization": "basic aGVsbG86d29ybGQ="} +should_keep_alive :0 +upgrade :"some data\r\nand yet even more data" +http_major :1 +http_minor :0 + +name :report request +raw :"REPORT /test HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_REPORT +status_code :0 +request_path:/test +request_url :/test +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :request with no http version +raw :"GET /\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/ +request_url :/ +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :0 +http_major :0 +http_minor :9 + +name :m-search request +raw :"M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nST: \"ssdp:all\"\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_MSEARCH +status_code :0 +request_path:* +request_url :* +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "HOST": "239.255.255.250:1900"} +header_1 :{ "MAN": ""ssdp:discover""} +header_2 :{ "ST": ""ssdp:all""} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :line folding in header value +raw :"GET / HTTP/1.1\r\nLine1: abc\r\n def\r\n ghi\r\n jkl\r\n mno \r\n qrs\r\nLine2: line2 \r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/ +request_url :/ +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Line1": "abcdefghijklmno qrs"} +header_1 :{ "Line2": "line2 "} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :host terminated by a query string +raw :"GET http://hypnotoad.org?hail=all HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path: +request_url :http://hypnotoad.org?hail=all +fragment : +query_string:hail=all +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :host:port terminated by a query string +raw :"GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path: +request_url :http://hypnotoad.org:1234?hail=all +fragment : +query_string:hail=all +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :host:port terminated by a space +raw :"GET http://hypnotoad.org:1234 HTTP/1.1\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path: +request_url :http://hypnotoad.org:1234 +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :PATCH request +raw :"PATCH /file.txt HTTP/1.1\r\nHost: www.example.com\r\nContent-Type: application/example\r\nIf-Match: \"e0023aa4e\"\r\nContent-Length: 10\r\n\r\ncccccccccc" +type :HTTP_REQUEST +method: UNKNOWN +status_code :0 +request_path:/file.txt +request_url :/file.txt +fragment : +query_string: +body :"cccccccccc" +body_size :0 +header_0 :{ "Host": "www.example.com"} +header_1 :{ "Content-Type": "application/example"} +header_2 :{ "If-Match": ""e0023aa4e""} +header_3 :{ "Content-Length": "10"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :connect caps request +raw :"CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\nUser-agent: Mozilla/1.1N\r\nProxy-authorization: basic aGVsbG86d29ybGQ=\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_CONNECT +status_code :0 +request_path: +request_url :HOME0.NETSCAPE.COM:443 +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "User-agent": "Mozilla/1.1N"} +header_1 :{ "Proxy-authorization": "basic aGVsbG86d29ybGQ="} +should_keep_alive :0 +upgrade :"" +http_major :1 +http_minor :0 + +name :eat CRLF between requests, no "Connection: close" header +raw :"POST / HTTP/1.1\r\nHost: www.example.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\n\r\nq=42\r\n" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/ +request_url :/ +fragment : +query_string: +body :"q=42" +body_size :0 +header_0 :{ "Host": "www.example.com"} +header_1 :{ "Content-Type": "application/x-www-form-urlencoded"} +header_2 :{ "Content-Length": "4"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :eat CRLF between requests even if "Connection: close" is set +raw :"POST / HTTP/1.1\r\nHost: www.example.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\nConnection: close\r\n\r\nq=42\r\n" +type :HTTP_REQUEST +method: HTTP_POST +status_code :0 +request_path:/ +request_url :/ +fragment : +query_string: +body :"q=42" +body_size :0 +header_0 :{ "Host": "www.example.com"} +header_1 :{ "Content-Type": "application/x-www-form-urlencoded"} +header_2 :{ "Content-Length": "4"} +header_3 :{ "Connection": "close"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :PURGE request +raw :"PURGE /file.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n" +type :HTTP_REQUEST +method: UNKNOWN +status_code :0 +request_path:/file.txt +request_url :/file.txt +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Host": "www.example.com"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :google 301 +raw :"HTTP/1.1 301 Moved Permanently\r\nLocation: http://www.google.com/\r\nContent-Type: text/html; charset=UTF-8\r\nDate: Sun, 26 Apr 2009 11:11:49 GMT\r\nExpires: Tue, 26 May 2009 11:11:49 GMT\r\nX-$PrototypeBI-Version: 1.6.0.3\r\nCache-Control: public, max-age=2592000\r\nServer: gws\r\nContent-Length: 219 \r\n\r\n\n301 Moved\n

    301 Moved

    \nThe document has moved\nhere.\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :301 +request_path: +request_url : +fragment : +query_string: +body :"\n301 Moved\n

    301 Moved

    \nThe document has moved\nhere.\r\n\r\n" +body_size :0 +header_0 :{ "Location": "http://www.google.com/"} +header_1 :{ "Content-Type": "text/html; charset=UTF-8"} +header_2 :{ "Date": "Sun, 26 Apr 2009 11:11:49 GMT"} +header_3 :{ "Expires": "Tue, 26 May 2009 11:11:49 GMT"} +header_4 :{ "X-$PrototypeBI-Version": "1.6.0.3"} +header_5 :{ "Cache-Control": "public, max-age=2592000"} +header_6 :{ "Server": "gws"} +header_7 :{ "Content-Length": "219 "} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :no content-length response +raw :"HTTP/1.1 200 OK\r\nDate: Tue, 04 Aug 2009 07:59:32 GMT\r\nServer: Apache\r\nX-Powered-By: Servlet/2.5 JSP/2.1\r\nContent-Type: text/xml; charset=utf-8\r\nConnection: close\r\n\r\n\n\n \n \n SOAP-ENV:Client\n Client Error\n \n \n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"\n\n \n \n SOAP-ENV:Client\n Client Error\n \n \n" +body_size :0 +header_0 :{ "Date": "Tue, 04 Aug 2009 07:59:32 GMT"} +header_1 :{ "Server": "Apache"} +header_2 :{ "X-Powered-By": "Servlet/2.5 JSP/2.1"} +header_3 :{ "Content-Type": "text/xml; charset=utf-8"} +header_4 :{ "Connection": "close"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :404 no headers no body +raw :"HTTP/1.1 404 Not Found\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :404 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :301 no response phrase +raw :"HTTP/1.1 301\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :301 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :200 trailing space on chunked body +raw :"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n25 \r\nThis is the data in the first chunk\r\n\r\n1C\r\nand this is the second one\r\n\r\n0 \r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"This is the data in the first chunk\r\nand this is the second one\r\n" +body_size :65 +header_0 :{ "Content-Type": "text/plain"} +header_1 :{ "Transfer-Encoding": "chunked"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :no carriage ret +raw :"HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\nConnection: close\n\nthese headers are from http://news.ycombinator.com/" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"these headers are from http://news.ycombinator.com/" +body_size :0 +header_0 :{ "Content-Type": "text/html; charset=utf-8"} +header_1 :{ "Connection": "close"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :proxy connection +raw :"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 11\r\nProxy-Connection: close\r\nDate: Thu, 31 Dec 2009 20:55:48 +0000\r\n\r\nhello world" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"hello world" +body_size :0 +header_0 :{ "Content-Type": "text/html; charset=UTF-8"} +header_1 :{ "Content-Length": "11"} +header_2 :{ "Proxy-Connection": "close"} +header_3 :{ "Date": "Thu, 31 Dec 2009 20:55:48 +0000"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :underscore header key +raw :"HTTP/1.1 200 OK\r\nServer: DCLK-AdSvr\r\nContent-Type: text/xml\r\nContent-Length: 0\r\nDCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Server": "DCLK-AdSvr"} +header_1 :{ "Content-Type": "text/xml"} +header_2 :{ "Content-Length": "0"} +header_3 :{ "DCLK_imp": "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o"} +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :bonjourmadame.fr +raw :"HTTP/1.0 301 Moved Permanently\r\nDate: Thu, 03 Jun 2010 09:56:32 GMT\r\nServer: Apache/2.2.3 (Red Hat)\r\nCache-Control: public\r\nPragma: \r\nLocation: http://www.bonjourmadame.fr/\r\nVary: Accept-Encoding\r\nContent-Length: 0\r\nContent-Type: text/html; charset=UTF-8\r\nConnection: keep-alive\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :301 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Date": "Thu, 03 Jun 2010 09:56:32 GMT"} +header_1 :{ "Server": "Apache/2.2.3 (Red Hat)"} +header_2 :{ "Cache-Control": "public"} +header_3 :{ "Pragma": ""} +header_4 :{ "Location": "http://www.bonjourmadame.fr/"} +header_5 :{ "Vary": "Accept-Encoding"} +header_6 :{ "Content-Length": "0"} +header_7 :{ "Content-Type": "text/html; charset=UTF-8"} +header_8 :{ "Connection": "keep-alive"} +should_keep_alive :1 +http_major :1 +http_minor :0 + +name :field underscore +raw :"HTTP/1.1 200 OK\r\nDate: Tue, 28 Sep 2010 01:14:13 GMT\r\nServer: Apache\r\nCache-Control: no-cache, must-revalidate\r\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\r\n.et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\nVary: Accept-Encoding\r\n_eep-Alive: timeout=45\r\n_onnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n0\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Date": "Tue, 28 Sep 2010 01:14:13 GMT"} +header_1 :{ "Server": "Apache"} +header_2 :{ "Cache-Control": "no-cache, must-revalidate"} +header_3 :{ "Expires": "Mon, 26 Jul 1997 05:00:00 GMT"} +header_4 :{ ".et-Cookie": "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com"} +header_5 :{ "Vary": "Accept-Encoding"} +header_6 :{ "_eep-Alive": "timeout=45"} +header_7 :{ "_onnection": "Keep-Alive"} +header_8 :{ "Transfer-Encoding": "chunked"} +header_9 :{ "Content-Type": "text/html"} +header_10 :{ "Connection": "close"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :non-ASCII in status line +raw :"HTTP/1.1 500 Oriëntatieprobleem\r\nDate: Fri, 5 Nov 2010 23:07:12 GMT+2\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :500 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Date": "Fri, 5 Nov 2010 23:07:12 GMT+2"} +header_1 :{ "Content-Length": "0"} +header_2 :{ "Connection": "close"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :http version 0.9 +raw :"HTTP/0.9 200 OK\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :0 +http_major :0 +http_minor :9 + +name :neither content-length nor transfer-encoding response +raw :"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello world" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"hello world" +body_size :0 +header_0 :{ "Content-Type": "text/plain"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :HTTP/1.0 with keep-alive and EOF-terminated 200 status +raw :"HTTP/1.0 200 OK\r\nConnection: keep-alive\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Connection": "keep-alive"} +should_keep_alive :0 +http_major :1 +http_minor :0 + +name :HTTP/1.0 with keep-alive and a 204 status +raw :"HTTP/1.0 204 No content\r\nConnection: keep-alive\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :204 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Connection": "keep-alive"} +should_keep_alive :1 +http_major :1 +http_minor :0 + +name :HTTP/1.1 with an EOF-terminated 200 status +raw :"HTTP/1.1 200 OK\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :HTTP/1.1 with a 204 status +raw :"HTTP/1.1 204 No content\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :204 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +should_keep_alive :1 +http_major :1 +http_minor :1 + +name :HTTP/1.1 with a 204 status and keep-alive disabled +raw :"HTTP/1.1 204 No content\r\nConnection: close\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :204 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Connection": "close"} +should_keep_alive :0 +http_major :1 +http_minor :1 + +name :HTTP/1.1 with chunked endocing and a 200 response +raw :"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n" +type :HTTP_RESPONSE +method: HTTP_DELETE +status_code :200 +request_path: +request_url : +fragment : +query_string: +body :"" +body_size :0 +header_0 :{ "Transfer-Encoding": "chunked"} +should_keep_alive :1 +http_major :1 +http_minor :1 + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 new file mode 100644 index 0000000..5266159 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 @@ -0,0 +1,17 @@ +name :utf-8 path request +raw :"GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\nHost: github.com\r\n\r\n" +type :HTTP_REQUEST +method: HTTP_GET +status_code :0 +request_path:/δ¶/δt/pope +request_url :/δ¶/δt/pope?q=1#narf +fragment :narf +query_string:q=1 +body :"" +body_size :0 +header_0 :{ "Host": "github.com"} +should_keep_alive :1 +upgrade :0 +http_major :1 +http_minor :1 + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb new file mode 100644 index 0000000..1604890 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb @@ -0,0 +1,6 @@ + +"A".upto("Z") {|c| + puts "public static final byte #{c} = 0x#{c[0].to_s(16)};" +} + + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb new file mode 100644 index 0000000..84f9699 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb @@ -0,0 +1,13 @@ + + +def printbytes str +str.each_byte { |b| + print "0x#{b.to_s(16)}, " +} +end + +if $0 == __FILE__ + printf "static final byte [] #{ARGV[0]} = {\n" + printbytes ARGV[0] + printf "\n};\n" +end diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb new file mode 100644 index 0000000..13960cb --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb @@ -0,0 +1,15 @@ + + +0.upto(255) { |i| + printf "\n" if i%16 == 0 + printf " " if i%8 == 0 + s = ("" << i) + if s =~ /[A-Z0-9\-_\/ ]/ + print "0x#{i.to_s(16)}," + elsif s =~ /[a-z]/ + print "0x#{s.upcase[0].to_s(16)}," + else + print "0x00," + end + +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb new file mode 100644 index 0000000..683adb9 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb @@ -0,0 +1,33 @@ + + + + +# name : 200 trailing space on chunked body +# raw : "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n25 \r\nThis is the data in the first chunk\r\n\r\n1C\r\nand this is the second one\r\n\r\n0 \r\n\r\n" +# type : HTTP_RESPONSE +# method: HTTP_DELETE +# status code :200 +# request_path: +# request_url : +# fragment : +# query_string: +# body :"This is the data in the first chunk\r\nand this is the second one\r\n" +# body_size :65 +# header_0 :{ "Content-Type": "text/plain"} +# header_1 :{ "Transfer-Encoding": "chunked"} +# should_keep_alive :1 +# upgrade :0 +# http_major :1 +# http_minor :1 + + +class ParserTest + attr_accessor :name + attr_accessor :raw + attr_accessor :type + attr_accessor :method + attr_accessor :status_code + attr_accessor :request_path + attr_accessor :method +end + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/AUTHORS b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/AUTHORS new file mode 100644 index 0000000..abe99de --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/AUTHORS @@ -0,0 +1,32 @@ +# Authors ordered by first contribution. +Ryan Dahl +Jeremy Hinegardner +Sergey Shepelev +Joe Damato +tomika +Phoenix Sol +Cliff Frey +Ewen Cheslack-Postava +Santiago Gala +Tim Becker +Jeff Terrace +Ben Noordhuis +Nathan Rajlich +Mark Nottingham +Aman Gupta +Tim Becker +Sean Cunningham +Peter Griess +Salman Haq +Cliff Frey +Jon Kolb +Fouad Mardini +Paul Querna +Felix Geisendörfer +koichik +Andre Caron +Ivo Raisr +James McLaughlin +David Gwynne +LE ROUX Thomas +Randy Rizun diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS new file mode 100644 index 0000000..11ba31e --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS @@ -0,0 +1,4 @@ +Contributors must agree to the Contributor License Agreement before patches +can be accepted. + +http://spreadsheets2.google.com/viewform?hl=en&formkey=dDJXOGUwbzlYaWM4cHN1MERwQS1CSnc6MQ diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT new file mode 100644 index 0000000..58010b3 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT @@ -0,0 +1,23 @@ +http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright +Igor Sysoev. + +Additional changes are licensed under the same terms as NGINX and +copyright Joyent, Inc. and other Node contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/README.md b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/README.md new file mode 100644 index 0000000..700c3ac --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/README.md @@ -0,0 +1,178 @@ +HTTP Parser +=========== + +This is a parser for HTTP messages written in C. It parses both requests and +responses. The parser is designed to be used in performance HTTP +applications. It does not make any syscalls nor allocations, it does not +buffer data, it can be interrupted at anytime. Depending on your +architecture, it only requires about 40 bytes of data per message +stream (in a web server that is per connection). + +Features: + + * No dependencies + * Handles persistent streams (keep-alive). + * Decodes chunked encoding. + * Upgrade support + * Defends against buffer overflow attacks. + +The parser extracts the following information from HTTP messages: + + * Header fields and values + * Content-Length + * Request method + * Response status code + * Transfer-Encoding + * HTTP version + * Request URL + * Message body + + +Usage +----- + +One `http_parser` object is used per TCP connection. Initialize the struct +using `http_parser_init()` and set the callbacks. That might look something +like this for a request parser: + + http_parser_settings settings; + settings.on_path = my_path_callback; + settings.on_header_field = my_header_field_callback; + /* ... */ + + http_parser *parser = malloc(sizeof(http_parser)); + http_parser_init(parser, HTTP_REQUEST); + parser->data = my_socket; + +When data is received on the socket execute the parser and check for errors. + + size_t len = 80*1024, nparsed; + char buf[len]; + ssize_t recved; + + recved = recv(fd, buf, len, 0); + + if (recved < 0) { + /* Handle error. */ + } + + /* Start up / continue the parser. + * Note we pass recved==0 to signal that EOF has been recieved. + */ + nparsed = http_parser_execute(parser, &settings, buf, recved); + + if (parser->upgrade) { + /* handle new protocol */ + } else if (nparsed != recved) { + /* Handle error. Usually just close the connection. */ + } + +HTTP needs to know where the end of the stream is. For example, sometimes +servers send responses without Content-Length and expect the client to +consume input (for the body) until EOF. To tell http_parser about EOF, give +`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors +can still be encountered during an EOF, so one must still be prepared +to receive them. + +Scalar valued message information such as `status_code`, `method`, and the +HTTP version are stored in the parser structure. This data is only +temporally stored in `http_parser` and gets reset on each new message. If +this information is needed later, copy it out of the structure during the +`headers_complete` callback. + +The parser decodes the transfer-encoding for both requests and responses +transparently. That is, a chunked encoding is decoded before being sent to +the on_body callback. + + +The Special Problem of Upgrade +------------------------------ + +HTTP supports upgrading the connection to a different protocol. An +increasingly common example of this is the Web Socket protocol which sends +a request like + + GET /demo HTTP/1.1 + Upgrade: WebSocket + Connection: Upgrade + Host: example.com + Origin: http://example.com + WebSocket-Protocol: sample + +followed by non-HTTP data. + +(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more +information the Web Socket protocol.) + +To support this, the parser will treat this as a normal HTTP message without a +body. Issuing both on_headers_complete and on_message_complete callbacks. However +http_parser_execute() will stop parsing at the end of the headers and return. + +The user is expected to check if `parser->upgrade` has been set to 1 after +`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied +offset by the return value of `http_parser_execute()`. + + +Callbacks +--------- + +During the `http_parser_execute()` call, the callbacks set in +`http_parser_settings` will be executed. The parser maintains state and +never looks behind, so buffering the data is not necessary. If you need to +save certain data for later usage, you can do that from the callbacks. + +There are two types of callbacks: + +* notification `typedef int (*http_cb) (http_parser*);` + Callbacks: on_message_begin, on_headers_complete, on_message_complete. +* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);` + Callbacks: (requests only) on_uri, + (common) on_header_field, on_header_value, on_body; + +Callbacks must return 0 on success. Returning a non-zero value indicates +error to the parser, making it exit immediately. + +In case you parse HTTP message in chunks (i.e. `read()` request line +from socket, parse, read half headers, parse, etc) your data callbacks +may be called more than once. Http-parser guarantees that data pointer is only +valid for the lifetime of callback. You can also `read()` into a heap allocated +buffer to avoid copying memory around if this fits your application. + +Reading headers may be a tricky task if you read/parse headers partially. +Basically, you need to remember whether last header callback was field or value +and apply following logic: + + (on_header_field and on_header_value shortened to on_h_*) + ------------------------ ------------ -------------------------------------------- + | State (prev. callback) | Callback | Description/action | + ------------------------ ------------ -------------------------------------------- + | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | + | | | into it | + ------------------------ ------------ -------------------------------------------- + | value | on_h_field | New header started. | + | | | Copy current name,value buffers to headers | + | | | list and allocate new buffer for new name | + ------------------------ ------------ -------------------------------------------- + | field | on_h_field | Previous name continues. Reallocate name | + | | | buffer and append callback data to it | + ------------------------ ------------ -------------------------------------------- + | field | on_h_value | Value for current header started. Allocate | + | | | new buffer and copy callback data to it | + ------------------------ ------------ -------------------------------------------- + | value | on_h_value | Value continues. Reallocate value buffer | + | | | and append callback data to it | + ------------------------ ------------ -------------------------------------------- + + +Parsing URLs +------------ + +A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`. +Users of this library may wish to use it to parse URLs constructed from +consecutive `on_url` callbacks. + +See examples of reading in headers: + +* [partial example](http://gist.github.com/155877) in C +* [from http-parser tests](http://github.com/ry/http-parser/blob/37a0ff8928fb0d83cec0d0d8909c5a4abcd221af/test.c#L403) in C +* [from Node library](http://github.com/ry/node/blob/842eaf446d2fdcb33b296c67c911c32a0dabc747/src/http.js#L284) in Javascript diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.c b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.c new file mode 100644 index 0000000..f2ca661 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.c @@ -0,0 +1,2058 @@ +/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev + * + * Additional changes are licensed under the same terms as NGINX and + * copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "http_parser.h" +#include +#include +#include +#include +#include +#include + +#ifndef ULLONG_MAX +# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +#if HTTP_PARSER_DEBUG +#define SET_ERRNO(e) \ +do { \ + parser->http_errno = (e); \ + parser->error_lineno = __LINE__; \ +} while (0) +#else +#define SET_ERRNO(e) \ +do { \ + parser->http_errno = (e); \ +} while(0) +#endif + + +/* Run the notify callback FOR, returning ER if it fails */ +#define CALLBACK_NOTIFY_(FOR, ER) \ +do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser)) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + \ + /* We either errored above or got paused; get out */ \ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ + return (ER); \ + } \ + } \ +} while (0) + +/* Run the notify callback FOR and consume the current byte */ +#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) + +/* Run the notify callback FOR and don't consume the current byte */ +#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) + +/* Run data callback FOR with LEN bytes, returning ER if it fails */ +#define CALLBACK_DATA_(FOR, LEN, ER) \ +do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (FOR##_mark) { \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + \ + /* We either errored above or got paused; get out */ \ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ + return (ER); \ + } \ + } \ + FOR##_mark = NULL; \ + } \ +} while (0) + +/* Run the data callback FOR and consume the current byte */ +#define CALLBACK_DATA(FOR) \ + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) + +/* Run the data callback FOR and don't consume the current byte */ +#define CALLBACK_DATA_NOADVANCE(FOR) \ + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) + +/* Set the mark FOR; non-destructive if mark is already set */ +#define MARK(FOR) \ +do { \ + if (!FOR##_mark) { \ + FOR##_mark = p; \ + } \ +} while (0) + + +#define PROXY_CONNECTION "proxy-connection" +#define CONNECTION "connection" +#define CONTENT_LENGTH "content-length" +#define TRANSFER_ENCODING "transfer-encoding" +#define UPGRADE "upgrade" +#define CHUNKED "chunked" +#define KEEP_ALIVE "keep-alive" +#define CLOSE "close" + + +static const char *method_strings[] = + { "DELETE" + , "GET" + , "HEAD" + , "POST" + , "PUT" + , "CONNECT" + , "OPTIONS" + , "TRACE" + , "COPY" + , "LOCK" + , "MKCOL" + , "MOVE" + , "PROPFIND" + , "PROPPATCH" + , "UNLOCK" + , "REPORT" + , "MKACTIVITY" + , "CHECKOUT" + , "MERGE" + , "M-SEARCH" + , "NOTIFY" + , "SUBSCRIBE" + , "UNSUBSCRIBE" + , "PATCH" + , "PURGE" + }; + + +/* Tokens as defined by rfc 2616. Also lowercases them. + * token = 1* + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + */ +static const char tokens[256] = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0, '!', 0, '#', '$', '%', '&', '\'', +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 0, 0, '*', '+', 0, '-', '.', 0, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + '0', '1', '2', '3', '4', '5', '6', '7', +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + '8', '9', 0, 0, 0, 0, 0, 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 'x', 'y', 'z', 0, 0, 0, '^', '_', +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 'x', 'y', 'z', 0, '|', 0, '~', 0 }; + + +static const int8_t unhex[256] = + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; + + +static const uint8_t normal_url_char[256] = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0, 1, 1, 0, 1, 1, 1, 1, +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + 1, 1, 1, 1, 1, 1, 1, 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 1, 1, 1, 1, 1, 1, 1, 1, +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 1, 1, 1, 1, 1, 1, 1, 0, }; + + +enum state + { s_dead = 1 /* important that this is > 0 */ + + , s_start_req_or_res + , s_res_or_resp_H + , s_start_res + , s_res_H + , s_res_HT + , s_res_HTT + , s_res_HTTP + , s_res_first_http_major + , s_res_http_major + , s_res_first_http_minor + , s_res_http_minor + , s_res_first_status_code + , s_res_status_code + , s_res_status + , s_res_line_almost_done + + , s_start_req + + , s_req_method + , s_req_spaces_before_url + , s_req_schema + , s_req_schema_slash + , s_req_schema_slash_slash + , s_req_host_start + , s_req_host_v6_start + , s_req_host_v6 + , s_req_host_v6_end + , s_req_host + , s_req_port_start + , s_req_port + , s_req_path + , s_req_query_string_start + , s_req_query_string + , s_req_fragment_start + , s_req_fragment + , s_req_http_start + , s_req_http_H + , s_req_http_HT + , s_req_http_HTT + , s_req_http_HTTP + , s_req_first_http_major + , s_req_http_major + , s_req_first_http_minor + , s_req_http_minor + , s_req_line_almost_done + + , s_header_field_start + , s_header_field + , s_header_value_start + , s_header_value + , s_header_value_lws + + , s_header_almost_done + + , s_chunk_size_start + , s_chunk_size + , s_chunk_parameters + , s_chunk_size_almost_done + + , s_headers_almost_done + , s_headers_done + + /* Important: 's_headers_done' must be the last 'header' state. All + * states beyond this must be 'body' states. It is used for overflow + * checking. See the PARSING_HEADER() macro. + */ + + , s_chunk_data + , s_chunk_data_almost_done + , s_chunk_data_done + + , s_body_identity + , s_body_identity_eof + + , s_message_done + }; + + +#define PARSING_HEADER(state) (state <= s_headers_done) + + +enum header_states + { h_general = 0 + , h_C + , h_CO + , h_CON + + , h_matching_connection + , h_matching_proxy_connection + , h_matching_content_length + , h_matching_transfer_encoding + , h_matching_upgrade + + , h_connection + , h_content_length + , h_transfer_encoding + , h_upgrade + + , h_matching_transfer_encoding_chunked + , h_matching_connection_keep_alive + , h_matching_connection_close + + , h_transfer_encoding_chunked + , h_connection_keep_alive + , h_connection_close + }; + + +/* Macros for character classes; depends on strict-mode */ +#define CR '\r' +#define LF '\n' +#define LOWER(c) (unsigned char)(c | 0x20) +#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') +#define IS_NUM(c) ((c) >= '0' && (c) <= '9') +#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) +#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) + +#if HTTP_PARSER_STRICT +#define TOKEN(c) (tokens[(unsigned char)c]) +#define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)]) +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') +#else +#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) +#define IS_URL_CHAR(c) \ + (normal_url_char[(unsigned char) (c)] || ((c) & 0x80)) +#define IS_HOST_CHAR(c) \ + (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') +#endif + + +#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) + + +#if HTTP_PARSER_STRICT +# define STRICT_CHECK(cond) \ +do { \ + if (cond) { \ + SET_ERRNO(HPE_STRICT); \ + goto error; \ + } \ +} while (0) +# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) +#else +# define STRICT_CHECK(cond) +# define NEW_MESSAGE() start_state +#endif + + +/* Map errno values to strings for human-readable output */ +#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, +static struct { + const char *name; + const char *description; +} http_strerror_tab[] = { + HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) +}; +#undef HTTP_STRERROR_GEN + +int http_message_needs_eof(http_parser *parser); + +/* Our URL parser. + * + * This is designed to be shared by http_parser_execute() for URL validation, + * hence it has a state transition + byte-for-byte interface. In addition, it + * is meant to be embedded in http_parser_parse_url(), which does the dirty + * work of turning state transitions URL components for its API. + * + * This function should only be invoked with non-space characters. It is + * assumed that the caller cares about (and can detect) the transition between + * URL and non-URL states by looking for these. + */ +static enum state +parse_url_char(enum state s, const char ch) +{ + assert(!isspace(ch)); + + switch (s) { + case s_req_spaces_before_url: + /* Proxied requests are followed by scheme of an absolute URI (alpha). + * All methods except CONNECT are followed by '/' or '*'. + */ + + if (ch == '/' || ch == '*') { + return s_req_path; + } + + if (IS_ALPHA(ch)) { + return s_req_schema; + } + + break; + + case s_req_schema: + if (IS_ALPHA(ch)) { + return s; + } + + if (ch == ':') { + return s_req_schema_slash; + } + + break; + + case s_req_schema_slash: + if (ch == '/') { + return s_req_schema_slash_slash; + } + + break; + + case s_req_schema_slash_slash: + if (ch == '/') { + return s_req_host_start; + } + + break; + + case s_req_host_start: + if (ch == '[') { + return s_req_host_v6_start; + } + + if (IS_HOST_CHAR(ch)) { + return s_req_host; + } + + break; + + case s_req_host: + if (IS_HOST_CHAR(ch)) { + return s_req_host; + } + + /* FALLTHROUGH */ + case s_req_host_v6_end: + switch (ch) { + case ':': + return s_req_port_start; + + case '/': + return s_req_path; + + case '?': + return s_req_query_string_start; + } + + break; + + case s_req_host_v6: + if (ch == ']') { + return s_req_host_v6_end; + } + + /* FALLTHROUGH */ + case s_req_host_v6_start: + if (IS_HEX(ch) || ch == ':') { + return s_req_host_v6; + } + break; + + case s_req_port: + switch (ch) { + case '/': + return s_req_path; + + case '?': + return s_req_query_string_start; + } + + /* FALLTHROUGH */ + case s_req_port_start: + if (IS_NUM(ch)) { + return s_req_port; + } + + break; + + case s_req_path: + if (IS_URL_CHAR(ch)) { + return s; + } + + switch (ch) { + case '?': + return s_req_query_string_start; + + case '#': + return s_req_fragment_start; + } + + break; + + case s_req_query_string_start: + case s_req_query_string: + if (IS_URL_CHAR(ch)) { + return s_req_query_string; + } + + switch (ch) { + case '?': + /* allow extra '?' in query string */ + return s_req_query_string; + + case '#': + return s_req_fragment_start; + } + + break; + + case s_req_fragment_start: + if (IS_URL_CHAR(ch)) { + return s_req_fragment; + } + + switch (ch) { + case '?': + return s_req_fragment; + + case '#': + return s; + } + + break; + + case s_req_fragment: + if (IS_URL_CHAR(ch)) { + return s; + } + + switch (ch) { + case '?': + case '#': + return s; + } + + break; + + default: + break; + } + + /* We should never fall out of the switch above unless there's an error */ + return s_dead; +} + +size_t http_parser_execute (http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len) +{ + char c, ch; + int8_t unhex_val; + const char *p = data; + const char *header_field_mark = 0; + const char *header_value_mark = 0; + const char *url_mark = 0; + const char *body_mark = 0; + + /* We're in an error state. Don't bother doing anything. */ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { + return 0; + } + + if (len == 0) { + switch (parser->state) { + case s_body_identity_eof: + /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if + * we got paused. + */ + CALLBACK_NOTIFY_NOADVANCE(message_complete); + return 0; + + case s_dead: + case s_start_req_or_res: + case s_start_res: + case s_start_req: + return 0; + + default: + SET_ERRNO(HPE_INVALID_EOF_STATE); + return 1; + } + } + + + if (parser->state == s_header_field) + header_field_mark = data; + if (parser->state == s_header_value) + header_value_mark = data; + switch (parser->state) { + case s_req_path: + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_host_start: + case s_req_host_v6_start: + case s_req_host_v6: + case s_req_host_v6_end: + case s_req_host: + case s_req_port_start: + case s_req_port: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + url_mark = data; + break; + } + + for (p=data; p != data + len; p++) { + ch = *p; + + if (PARSING_HEADER(parser->state)) { + ++parser->nread; + /* Buffer overflow attack */ + if (parser->nread > HTTP_MAX_HEADER_SIZE) { + SET_ERRNO(HPE_HEADER_OVERFLOW); + goto error; + } + } + + reexecute_byte: + switch (parser->state) { + + case s_dead: + /* this state is used after a 'Connection: close' message + * the parser will error out if it reads another message + */ + if (ch == CR || ch == LF) + break; + + SET_ERRNO(HPE_CLOSED_CONNECTION); + goto error; + + case s_start_req_or_res: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (ch == 'H') { + parser->state = s_res_or_resp_H; + + CALLBACK_NOTIFY(message_begin); + } else { + parser->type = HTTP_REQUEST; + parser->state = s_start_req; + goto reexecute_byte; + } + + break; + } + + case s_res_or_resp_H: + if (ch == 'T') { + parser->type = HTTP_RESPONSE; + parser->state = s_res_HT; + } else { + if (ch != 'E') { + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + parser->type = HTTP_REQUEST; + parser->method = HTTP_HEAD; + parser->index = 2; + parser->state = s_req_method; + } + break; + + case s_start_res: + { + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + switch (ch) { + case 'H': + parser->state = s_res_H; + break; + + case CR: + case LF: + break; + + default: + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + CALLBACK_NOTIFY(message_begin); + break; + } + + case s_res_H: + STRICT_CHECK(ch != 'T'); + parser->state = s_res_HT; + break; + + case s_res_HT: + STRICT_CHECK(ch != 'T'); + parser->state = s_res_HTT; + break; + + case s_res_HTT: + STRICT_CHECK(ch != 'P'); + parser->state = s_res_HTTP; + break; + + case s_res_HTTP: + STRICT_CHECK(ch != '/'); + parser->state = s_res_first_http_major; + break; + + case s_res_first_http_major: + if (ch < '0' || ch > '9') { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + parser->state = s_res_http_major; + break; + + /* major HTTP version or dot */ + case s_res_http_major: + { + if (ch == '.') { + parser->state = s_res_first_http_minor; + break; + } + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + /* first digit of minor HTTP version */ + case s_res_first_http_minor: + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + parser->state = s_res_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_res_http_minor: + { + if (ch == ' ') { + parser->state = s_res_first_status_code; + break; + } + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + case s_res_first_status_code: + { + if (!IS_NUM(ch)) { + if (ch == ' ') { + break; + } + + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + parser->status_code = ch - '0'; + parser->state = s_res_status_code; + break; + } + + case s_res_status_code: + { + if (!IS_NUM(ch)) { + switch (ch) { + case ' ': + parser->state = s_res_status; + break; + case CR: + parser->state = s_res_line_almost_done; + break; + case LF: + parser->state = s_header_field_start; + break; + default: + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + break; + } + + parser->status_code *= 10; + parser->status_code += ch - '0'; + + if (parser->status_code > 999) { + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + + break; + } + + case s_res_status: + /* the human readable status. e.g. "NOT FOUND" + * we are not humans so just ignore this */ + if (ch == CR) { + parser->state = s_res_line_almost_done; + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + break; + } + break; + + case s_res_line_almost_done: + STRICT_CHECK(ch != LF); + parser->state = s_header_field_start; + break; + + case s_start_req: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (!IS_ALPHA(ch)) { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + parser->method = (enum http_method) 0; + parser->index = 1; + switch (ch) { + case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; + case 'D': parser->method = HTTP_DELETE; break; + case 'G': parser->method = HTTP_GET; break; + case 'H': parser->method = HTTP_HEAD; break; + case 'L': parser->method = HTTP_LOCK; break; + case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; + case 'N': parser->method = HTTP_NOTIFY; break; + case 'O': parser->method = HTTP_OPTIONS; break; + case 'P': parser->method = HTTP_POST; + /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ + break; + case 'R': parser->method = HTTP_REPORT; break; + case 'S': parser->method = HTTP_SUBSCRIBE; break; + case 'T': parser->method = HTTP_TRACE; break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; + default: + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + parser->state = s_req_method; + + CALLBACK_NOTIFY(message_begin); + + break; + } + + case s_req_method: + { + const char *matcher; + if (ch == '\0') { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + matcher = method_strings[parser->method]; + if (ch == ' ' && matcher[parser->index] == '\0') { + parser->state = s_req_spaces_before_url; + } else if (ch == matcher[parser->index]) { + ; /* nada */ + } else if (parser->method == HTTP_CONNECT) { + if (parser->index == 1 && ch == 'H') { + parser->method = HTTP_CHECKOUT; + } else if (parser->index == 2 && ch == 'P') { + parser->method = HTTP_COPY; + } else { + goto error; + } + } else if (parser->method == HTTP_MKCOL) { + if (parser->index == 1 && ch == 'O') { + parser->method = HTTP_MOVE; + } else if (parser->index == 1 && ch == 'E') { + parser->method = HTTP_MERGE; + } else if (parser->index == 1 && ch == '-') { + parser->method = HTTP_MSEARCH; + } else if (parser->index == 2 && ch == 'A') { + parser->method = HTTP_MKACTIVITY; + } else { + goto error; + } + } else if (parser->index == 1 && parser->method == HTTP_POST) { + if (ch == 'R') { + parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ + } else if (ch == 'U') { + parser->method = HTTP_PUT; /* or HTTP_PURGE */ + } else if (ch == 'A') { + parser->method = HTTP_PATCH; + } else { + goto error; + } + } else if (parser->index == 2) { + if (parser->method == HTTP_PUT) { + if (ch == 'R') parser->method = HTTP_PURGE; + } else if (parser->method == HTTP_UNLOCK) { + if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE; + } + } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { + parser->method = HTTP_PROPPATCH; + } else { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + ++parser->index; + break; + } + + case s_req_spaces_before_url: + { + if (ch == ' ') break; + + MARK(url); + if (parser->method == HTTP_CONNECT) { + parser->state = s_req_host_start; + } + + parser->state = parse_url_char((enum state)parser->state, ch); + if (parser->state == s_dead) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + + break; + } + + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_host_start: + case s_req_host_v6_start: + case s_req_host_v6: + case s_req_port_start: + { + switch (ch) { + /* No whitespace allowed here */ + case ' ': + case CR: + case LF: + SET_ERRNO(HPE_INVALID_URL); + goto error; + default: + parser->state = parse_url_char((enum state)parser->state, ch); + if (parser->state == s_dead) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + + break; + } + + case s_req_host: + case s_req_host_v6_end: + case s_req_port: + case s_req_path: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + { + switch (ch) { + case ' ': + parser->state = s_req_http_start; + CALLBACK_DATA(url); + break; + case CR: + case LF: + parser->http_major = 0; + parser->http_minor = 9; + parser->state = (ch == CR) ? + s_req_line_almost_done : + s_header_field_start; + CALLBACK_DATA(url); + break; + default: + parser->state = parse_url_char((enum state)parser->state, ch); + if (parser->state == s_dead) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + break; + } + + case s_req_http_start: + switch (ch) { + case 'H': + parser->state = s_req_http_H; + break; + case ' ': + break; + default: + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + break; + + case s_req_http_H: + STRICT_CHECK(ch != 'T'); + parser->state = s_req_http_HT; + break; + + case s_req_http_HT: + STRICT_CHECK(ch != 'T'); + parser->state = s_req_http_HTT; + break; + + case s_req_http_HTT: + STRICT_CHECK(ch != 'P'); + parser->state = s_req_http_HTTP; + break; + + case s_req_http_HTTP: + STRICT_CHECK(ch != '/'); + parser->state = s_req_first_http_major; + break; + + /* first digit of major HTTP version */ + case s_req_first_http_major: + if (ch < '1' || ch > '9') { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + parser->state = s_req_http_major; + break; + + /* major HTTP version or dot */ + case s_req_http_major: + { + if (ch == '.') { + parser->state = s_req_first_http_minor; + break; + } + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + /* first digit of minor HTTP version */ + case s_req_first_http_minor: + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + parser->state = s_req_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_req_http_minor: + { + if (ch == CR) { + parser->state = s_req_line_almost_done; + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + break; + } + + /* XXX allow spaces after digit? */ + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + break; + } + + /* end of request line */ + case s_req_line_almost_done: + { + if (ch != LF) { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } + + parser->state = s_header_field_start; + break; + } + + case s_header_field_start: + { + if (ch == CR) { + parser->state = s_headers_almost_done; + break; + } + + if (ch == LF) { + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + parser->state = s_headers_almost_done; + goto reexecute_byte; + } + + c = TOKEN(ch); + + if (!c) { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + MARK(header_field); + + parser->index = 0; + parser->state = s_header_field; + + switch (c) { + case 'c': + parser->header_state = h_C; + break; + + case 'p': + parser->header_state = h_matching_proxy_connection; + break; + + case 't': + parser->header_state = h_matching_transfer_encoding; + break; + + case 'u': + parser->header_state = h_matching_upgrade; + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_field: + { + c = TOKEN(ch); + + if (c) { + switch (parser->header_state) { + case h_general: + break; + + case h_C: + parser->index++; + parser->header_state = (c == 'o' ? h_CO : h_general); + break; + + case h_CO: + parser->index++; + parser->header_state = (c == 'n' ? h_CON : h_general); + break; + + case h_CON: + parser->index++; + switch (c) { + case 'n': + parser->header_state = h_matching_connection; + break; + case 't': + parser->header_state = h_matching_content_length; + break; + default: + parser->header_state = h_general; + break; + } + break; + + /* connection */ + + case h_matching_connection: + parser->index++; + if (parser->index > sizeof(CONNECTION)-1 + || c != CONNECTION[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CONNECTION)-2) { + parser->header_state = h_connection; + } + break; + + /* proxy-connection */ + + case h_matching_proxy_connection: + parser->index++; + if (parser->index > sizeof(PROXY_CONNECTION)-1 + || c != PROXY_CONNECTION[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { + parser->header_state = h_connection; + } + break; + + /* content-length */ + + case h_matching_content_length: + parser->index++; + if (parser->index > sizeof(CONTENT_LENGTH)-1 + || c != CONTENT_LENGTH[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { + parser->header_state = h_content_length; + } + break; + + /* transfer-encoding */ + + case h_matching_transfer_encoding: + parser->index++; + if (parser->index > sizeof(TRANSFER_ENCODING)-1 + || c != TRANSFER_ENCODING[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { + parser->header_state = h_transfer_encoding; + } + break; + + /* upgrade */ + + case h_matching_upgrade: + parser->index++; + if (parser->index > sizeof(UPGRADE)-1 + || c != UPGRADE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(UPGRADE)-2) { + parser->header_state = h_upgrade; + } + break; + + case h_connection: + case h_content_length: + case h_transfer_encoding: + case h_upgrade: + if (ch != ' ') parser->header_state = h_general; + break; + + default: + assert(0 && "Unknown header_state"); + break; + } + break; + } + + if (ch == ':') { + parser->state = s_header_value_start; + CALLBACK_DATA(header_field); + break; + } + + if (ch == CR) { + parser->state = s_header_almost_done; + CALLBACK_DATA(header_field); + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + CALLBACK_DATA(header_field); + break; + } + + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + case s_header_value_start: + { + if (ch == ' ' || ch == '\t') break; + + MARK(header_value); + + parser->state = s_header_value; + parser->index = 0; + + if (ch == CR) { + parser->header_state = h_general; + parser->state = s_header_almost_done; + CALLBACK_DATA(header_value); + break; + } + + if (ch == LF) { + parser->state = s_header_field_start; + CALLBACK_DATA(header_value); + break; + } + + c = LOWER(ch); + + switch (parser->header_state) { + case h_upgrade: + parser->flags |= F_UPGRADE; + parser->header_state = h_general; + break; + + case h_transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if ('c' == c) { + parser->header_state = h_matching_transfer_encoding_chunked; + } else { + parser->header_state = h_general; + } + break; + + case h_content_length: + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = ch - '0'; + break; + + case h_connection: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') { + parser->header_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (c == 'c') { + parser->header_state = h_matching_connection_close; + } else { + parser->header_state = h_general; + } + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_value: + { + + if (ch == CR) { + parser->state = s_header_almost_done; + CALLBACK_DATA(header_value); + break; + } + + if (ch == LF) { + parser->state = s_header_almost_done; + CALLBACK_DATA_NOADVANCE(header_value); + goto reexecute_byte; + } + + c = LOWER(ch); + + switch (parser->header_state) { + case h_general: + break; + + case h_connection: + case h_transfer_encoding: + assert(0 && "Shouldn't get here."); + break; + + case h_content_length: + { + uint64_t t; + + if (ch == ' ') break; + + if (!IS_NUM(ch)) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + t = parser->content_length; + t *= 10; + t += ch - '0'; + + /* Overflow? */ + if (t < parser->content_length || t == ULLONG_MAX) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = t; + break; + } + + /* Transfer-Encoding: chunked */ + case h_matching_transfer_encoding_chunked: + parser->index++; + if (parser->index > sizeof(CHUNKED)-1 + || c != CHUNKED[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CHUNKED)-2) { + parser->header_state = h_transfer_encoding_chunked; + } + break; + + /* looking for 'Connection: keep-alive' */ + case h_matching_connection_keep_alive: + parser->index++; + if (parser->index > sizeof(KEEP_ALIVE)-1 + || c != KEEP_ALIVE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(KEEP_ALIVE)-2) { + parser->header_state = h_connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case h_matching_connection_close: + parser->index++; + if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CLOSE)-2) { + parser->header_state = h_connection_close; + } + break; + + case h_transfer_encoding_chunked: + case h_connection_keep_alive: + case h_connection_close: + if (ch != ' ') parser->header_state = h_general; + break; + + default: + parser->state = s_header_value; + parser->header_state = h_general; + break; + } + break; + } + + case s_header_almost_done: + { + STRICT_CHECK(ch != LF); + + parser->state = s_header_value_lws; + + switch (parser->header_state) { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + default: + break; + } + + break; + } + + case s_header_value_lws: + { + if (ch == ' ' || ch == '\t') + parser->state = s_header_value_start; + else + { + parser->state = s_header_field_start; + goto reexecute_byte; + } + break; + } + + case s_headers_almost_done: + { + STRICT_CHECK(ch != LF); + + if (parser->flags & F_TRAILING) { + /* End of a chunked request */ + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + break; + } + + parser->state = s_headers_done; + + /* Set this here so that on_headers_complete() callbacks can see it */ + parser->upgrade = + (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); + + /* Here we call the headers_complete callback. This is somewhat + * different than other callbacks because if the user returns 1, we + * will interpret that as saying that this message has no body. This + * is needed for the annoying case of recieving a response to a HEAD + * request. + * + * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so + * we have to simulate it by handling a change in errno below. + */ + if (settings->on_headers_complete) { + switch (settings->on_headers_complete(parser)) { + case 0: + break; + + case 1: + parser->flags |= F_SKIPBODY; + break; + + default: + SET_ERRNO(HPE_CB_headers_complete); + return p - data; /* Error */ + } + } + + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { + return p - data; + } + + goto reexecute_byte; + } + + case s_headers_done: + { + STRICT_CHECK(ch != LF); + + parser->nread = 0; + + /* Exit, the rest of the connect is in a different protocol. */ + if (parser->upgrade) { + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + return (p - data) + 1; + } + + if (parser->flags & F_SKIPBODY) { + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + parser->state = s_chunk_size_start; + } else { + if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + } else if (parser->content_length != ULLONG_MAX) { + /* Content-Length header given and non-zero */ + parser->state = s_body_identity; + } else { + if (parser->type == HTTP_REQUEST || + !http_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + } else { + /* Read body until EOF */ + parser->state = s_body_identity_eof; + } + } + } + + break; + } + + case s_body_identity: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t) ((data + len) - p)); + + assert(parser->content_length != 0 + && parser->content_length != ULLONG_MAX); + + /* The difference between advancing content_length and p is because + * the latter will automaticaly advance on the next loop iteration. + * Further, if content_length ends up at 0, we want to see the last + * byte again for our message complete callback. + */ + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; + + if (parser->content_length == 0) { + parser->state = s_message_done; + + /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. + * + * The alternative to doing this is to wait for the next byte to + * trigger the data callback, just as in every other case. The + * problem with this is that this makes it difficult for the test + * harness to distinguish between complete-on-EOF and + * complete-on-length. It's not clear that this distinction is + * important for applications, but let's keep it for now. + */ + CALLBACK_DATA_(body, p - body_mark + 1, p - data); + goto reexecute_byte; + } + + break; + } + + /* read until EOF */ + case s_body_identity_eof: + MARK(body); + p = data + len - 1; + + break; + + case s_message_done: + parser->state = NEW_MESSAGE(); + CALLBACK_NOTIFY(message_complete); + break; + + case s_chunk_size_start: + { + assert(parser->nread == 1); + assert(parser->flags & F_CHUNKED); + + unhex_val = unhex[(unsigned char)ch]; + if (unhex_val == -1) { + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } + + parser->content_length = unhex_val; + parser->state = s_chunk_size; + break; + } + + case s_chunk_size: + { + uint64_t t; + + assert(parser->flags & F_CHUNKED); + + if (ch == CR) { + parser->state = s_chunk_size_almost_done; + break; + } + + unhex_val = unhex[(unsigned char)ch]; + + if (unhex_val == -1) { + if (ch == ';' || ch == ' ') { + parser->state = s_chunk_parameters; + break; + } + + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } + + t = parser->content_length; + t *= 16; + t += unhex_val; + + /* Overflow? */ + if (t < parser->content_length || t == ULLONG_MAX) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = t; + break; + } + + case s_chunk_parameters: + { + assert(parser->flags & F_CHUNKED); + /* just ignore this shit. TODO check for overflow */ + if (ch == CR) { + parser->state = s_chunk_size_almost_done; + break; + } + break; + } + + case s_chunk_size_almost_done: + { + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + + parser->nread = 0; + + if (parser->content_length == 0) { + parser->flags |= F_TRAILING; + parser->state = s_header_field_start; + } else { + parser->state = s_chunk_data; + } + break; + } + + case s_chunk_data: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t) ((data + len) - p)); + + assert(parser->flags & F_CHUNKED); + assert(parser->content_length != 0 + && parser->content_length != ULLONG_MAX); + + /* See the explanation in s_body_identity for why the content + * length and data pointers are managed this way. + */ + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; + + if (parser->content_length == 0) { + parser->state = s_chunk_data_almost_done; + } + + break; + } + + case s_chunk_data_almost_done: + assert(parser->flags & F_CHUNKED); + assert(parser->content_length == 0); + STRICT_CHECK(ch != CR); + parser->state = s_chunk_data_done; + CALLBACK_DATA(body); + break; + + case s_chunk_data_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + parser->nread = 0; + parser->state = s_chunk_size_start; + break; + + default: + assert(0 && "unhandled state"); + SET_ERRNO(HPE_INVALID_INTERNAL_STATE); + goto error; + } + } + + /* Run callbacks for any marks that we have leftover after we ran our of + * bytes. There should be at most one of these set, so it's OK to invoke + * them in series (unset marks will not result in callbacks). + * + * We use the NOADVANCE() variety of callbacks here because 'p' has already + * overflowed 'data' and this allows us to correct for the off-by-one that + * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' + * value that's in-bounds). + */ + + assert(((header_field_mark ? 1 : 0) + + (header_value_mark ? 1 : 0) + + (url_mark ? 1 : 0) + + (body_mark ? 1 : 0)) <= 1); + + CALLBACK_DATA_NOADVANCE(header_field); + CALLBACK_DATA_NOADVANCE(header_value); + CALLBACK_DATA_NOADVANCE(url); + CALLBACK_DATA_NOADVANCE(body); + + return len; + +error: + if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { + SET_ERRNO(HPE_UNKNOWN); + } + + return (p - data); +} + + +/* Does the parser need to see an EOF to find the end of the message? */ +int +http_message_needs_eof (http_parser *parser) +{ + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + parser->flags & F_SKIPBODY) { /* response to a HEAD request */ + return 0; + } + + if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { + return 0; + } + + return 1; +} + + +int +http_should_keep_alive (http_parser *parser) +{ + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !http_message_needs_eof(parser); +} + + +const char * http_method_str (enum http_method m) +{ + return method_strings[m]; +} + + +void +http_parser_init (http_parser *parser, enum http_parser_type t) +{ + void *data = parser->data; /* preserve application data */ + memset(parser, 0, sizeof(*parser)); + parser->data = data; + parser->type = t; + parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); + parser->http_errno = HPE_OK; +} + +const char * +http_errno_name(enum http_errno err) { + assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); + return http_strerror_tab[err].name; +} + +const char * +http_errno_description(enum http_errno err) { + assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); + return http_strerror_tab[err].description; +} + +int +http_parser_parse_url(const char *buf, size_t buflen, int is_connect, + struct http_parser_url *u) +{ + enum state s; + const char *p; + enum http_parser_url_fields uf, old_uf; + + u->port = u->field_set = 0; + s = is_connect ? s_req_host_start : s_req_spaces_before_url; + uf = old_uf = UF_MAX; + + for (p = buf; p < buf + buflen; p++) { + s = parse_url_char(s, *p); + + /* Figure out the next field that we're operating on */ + switch (s) { + case s_dead: + return 1; + + /* Skip delimeters */ + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_host_start: + case s_req_host_v6_start: + case s_req_host_v6_end: + case s_req_port_start: + case s_req_query_string_start: + case s_req_fragment_start: + continue; + + case s_req_schema: + uf = UF_SCHEMA; + break; + + case s_req_host: + case s_req_host_v6: + uf = UF_HOST; + break; + + case s_req_port: + uf = UF_PORT; + break; + + case s_req_path: + uf = UF_PATH; + break; + + case s_req_query_string: + uf = UF_QUERY; + break; + + case s_req_fragment: + uf = UF_FRAGMENT; + break; + + default: + assert(!"Unexpected state"); + return 1; + } + + /* Nothing's changed; soldier on */ + if (uf == old_uf) { + u->field_data[uf].len++; + continue; + } + + u->field_data[uf].off = p - buf; + u->field_data[uf].len = 1; + + u->field_set |= (1 << uf); + old_uf = uf; + } + + /* CONNECT requests can only contain "hostname:port" */ + if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { + return 1; + } + + /* Make sure we don't end somewhere unexpected */ + switch (s) { + case s_req_host_v6_start: + case s_req_host_v6: + case s_req_host_v6_end: + case s_req_host: + case s_req_port_start: + return 1; + default: + break; + } + + if (u->field_set & (1 << UF_PORT)) { + /* Don't bother with endp; we've already validated the string */ + unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); + + /* Ports have a max value of 2^16 */ + if (v > 0xffff) { + return 1; + } + + u->port = (uint16_t) v; + } + + return 0; +} + +void +http_parser_pause(http_parser *parser, int paused) { + /* Users should only be pausing/unpausing a parser that is not in an error + * state. In non-debug builds, there's not much that we can do about this + * other than ignore it. + */ + if (HTTP_PARSER_ERRNO(parser) == HPE_OK || + HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { + SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); + } else { + assert(0 && "Attempting to pause parser in error state"); + } +} diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp new file mode 100644 index 0000000..c6eada7 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp @@ -0,0 +1,79 @@ +# This file is used with the GYP meta build system. +# http://code.google.com/p/gyp/ +# To build try this: +# svn co http://gyp.googlecode.com/svn/trunk gyp +# ./gyp/gyp -f make --depth=`pwd` http_parser.gyp +# ./out/Debug/test +{ + 'target_defaults': { + 'default_configuration': 'Debug', + 'configurations': { + # TODO: hoist these out and put them somewhere common, because + # RuntimeLibrary MUST MATCH across the entire project + 'Debug': { + 'defines': [ 'DEBUG', '_DEBUG' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 1, # static debug + }, + }, + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 0, # static release + }, + }, + } + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + }, + 'VCLibrarianTool': { + }, + 'VCLinkerTool': { + 'GenerateDebugInformation': 'true', + }, + }, + 'conditions': [ + ['OS == "win"', { + 'defines': [ + 'WIN32' + ], + }] + ], + }, + + 'targets': [ + { + 'target_name': 'http_parser', + 'type': 'static_library', + 'include_dirs': [ '.' ], + 'direct_dependent_settings': { + 'include_dirs': [ '.' ], + }, + 'defines': [ 'HTTP_PARSER_STRICT=0' ], + 'sources': [ './http_parser.c', ], + 'conditions': [ + ['OS=="win"', { + 'msvs_settings': { + 'VCCLCompilerTool': { + # Compile as C++. http_parser.c is actually C99, but C++ is + # close enough in this case. + 'CompileAs': 2, + }, + }, + }] + ], + }, + + { + 'target_name': 'test', + 'type': 'executable', + 'dependencies': [ 'http_parser' ], + 'sources': [ 'test.c' ] + } + ] +} + diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.h b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.h new file mode 100644 index 0000000..78b3701 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/http_parser.h @@ -0,0 +1,312 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef http_parser_h +#define http_parser_h +#ifdef __cplusplus +extern "C" { +#endif + +#define HTTP_PARSER_VERSION_MAJOR 1 +#define HTTP_PARSER_VERSION_MINOR 0 + +#include +#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +typedef unsigned int size_t; +typedef int ssize_t; +#else +#include +#endif + +/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run + * faster + */ +#ifndef HTTP_PARSER_STRICT +# define HTTP_PARSER_STRICT 1 +#endif + +/* Compile with -DHTTP_PARSER_DEBUG=1 to add extra debugging information to + * the error reporting facility. + */ +#ifndef HTTP_PARSER_DEBUG +# define HTTP_PARSER_DEBUG 0 +#endif + + +/* Maximium header size allowed */ +#define HTTP_MAX_HEADER_SIZE (80*1024) + + +typedef struct http_parser http_parser; +typedef struct http_parser_settings http_parser_settings; +typedef struct http_parser_result http_parser_result; + + +/* Callbacks should return non-zero to indicate an error. The parser will + * then halt execution. + * + * The one exception is on_headers_complete. In a HTTP_RESPONSE parser + * returning '1' from on_headers_complete will tell the parser that it + * should not expect a body. This is used when receiving a response to a + * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: + * chunked' headers that indicate the presence of a body. + * + * http_data_cb does not return data chunks. It will be call arbitrarally + * many times for each string. E.G. you might get 10 callbacks for "on_path" + * each providing just a few characters more data. + */ +typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); +typedef int (*http_cb) (http_parser*); + + +/* Request Methods */ +enum http_method + { HTTP_DELETE = 0 + , HTTP_GET + , HTTP_HEAD + , HTTP_POST + , HTTP_PUT + /* pathological */ + , HTTP_CONNECT + , HTTP_OPTIONS + , HTTP_TRACE + /* webdav */ + , HTTP_COPY + , HTTP_LOCK + , HTTP_MKCOL + , HTTP_MOVE + , HTTP_PROPFIND + , HTTP_PROPPATCH + , HTTP_UNLOCK + /* subversion */ + , HTTP_REPORT + , HTTP_MKACTIVITY + , HTTP_CHECKOUT + , HTTP_MERGE + /* upnp */ + , HTTP_MSEARCH + , HTTP_NOTIFY + , HTTP_SUBSCRIBE + , HTTP_UNSUBSCRIBE + /* RFC-5789 */ + , HTTP_PATCH + , HTTP_PURGE + }; + + +enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; + + +/* Flag values for http_parser.flags field */ +enum flags + { F_CHUNKED = 1 << 0 + , F_CONNECTION_KEEP_ALIVE = 1 << 1 + , F_CONNECTION_CLOSE = 1 << 2 + , F_TRAILING = 1 << 3 + , F_UPGRADE = 1 << 4 + , F_SKIPBODY = 1 << 5 + }; + + +/* Map for errno-related constants + * + * The provided argument should be a macro that takes 2 arguments. + */ +#define HTTP_ERRNO_MAP(XX) \ + /* No error */ \ + XX(OK, "success") \ + \ + /* Callback-related errors */ \ + XX(CB_message_begin, "the on_message_begin callback failed") \ + XX(CB_url, "the on_url callback failed") \ + XX(CB_header_field, "the on_header_field callback failed") \ + XX(CB_header_value, "the on_header_value callback failed") \ + XX(CB_headers_complete, "the on_headers_complete callback failed") \ + XX(CB_body, "the on_body callback failed") \ + XX(CB_message_complete, "the on_message_complete callback failed") \ + \ + /* Parsing-related errors */ \ + XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ + XX(HEADER_OVERFLOW, \ + "too many header bytes seen; overflow detected") \ + XX(CLOSED_CONNECTION, \ + "data received after completed connection: close message") \ + XX(INVALID_VERSION, "invalid HTTP version") \ + XX(INVALID_STATUS, "invalid HTTP status code") \ + XX(INVALID_METHOD, "invalid HTTP method") \ + XX(INVALID_URL, "invalid URL") \ + XX(INVALID_HOST, "invalid host") \ + XX(INVALID_PORT, "invalid port") \ + XX(INVALID_PATH, "invalid path") \ + XX(INVALID_QUERY_STRING, "invalid query string") \ + XX(INVALID_FRAGMENT, "invalid fragment") \ + XX(LF_EXPECTED, "LF character expected") \ + XX(INVALID_HEADER_TOKEN, "invalid character in header") \ + XX(INVALID_CONTENT_LENGTH, \ + "invalid character in content-length header") \ + XX(INVALID_CHUNK_SIZE, \ + "invalid character in chunk size header") \ + XX(INVALID_CONSTANT, "invalid constant string") \ + XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ + XX(STRICT, "strict mode assertion failed") \ + XX(PAUSED, "parser is paused") \ + XX(UNKNOWN, "an unknown error occurred") + + +/* Define HPE_* values for each errno value above */ +#define HTTP_ERRNO_GEN(n, s) HPE_##n, +enum http_errno { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) +}; +#undef HTTP_ERRNO_GEN + + +/* Get an http_errno value from an http_parser */ +#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) + +/* Get the line number that generated the current error */ +#if HTTP_PARSER_DEBUG +#define HTTP_PARSER_ERRNO_LINE(p) ((p)->error_lineno) +#else +#define HTTP_PARSER_ERRNO_LINE(p) 0 +#endif + + +struct http_parser { + /** PRIVATE **/ + unsigned char type : 2; /* enum http_parser_type */ + unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ + unsigned char state; /* enum state from http_parser.c */ + unsigned char header_state; /* enum header_state from http_parser.c */ + unsigned char index; /* index into current matcher */ + + uint32_t nread; /* # bytes read in various scenarios */ + uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ + + /** READ-ONLY **/ + unsigned short http_major; + unsigned short http_minor; + unsigned short status_code; /* responses only */ + unsigned char method; /* requests only */ + unsigned char http_errno : 7; + + /* 1 = Upgrade header was present and the parser has exited because of that. + * 0 = No upgrade header present. + * Should be checked when http_parser_execute() returns in addition to + * error checking. + */ + unsigned char upgrade : 1; + +#if HTTP_PARSER_DEBUG + uint32_t error_lineno; +#endif + + /** PUBLIC **/ + void *data; /* A pointer to get hook to the "connection" or "socket" object */ +}; + + +struct http_parser_settings { + http_cb on_message_begin; + http_data_cb on_url; + http_data_cb on_header_field; + http_data_cb on_header_value; + http_cb on_headers_complete; + http_data_cb on_body; + http_cb on_message_complete; +}; + + +enum http_parser_url_fields + { UF_SCHEMA = 0 + , UF_HOST = 1 + , UF_PORT = 2 + , UF_PATH = 3 + , UF_QUERY = 4 + , UF_FRAGMENT = 5 + , UF_MAX = 6 + }; + + +/* Result structure for http_parser_parse_url(). + * + * Callers should index into field_data[] with UF_* values iff field_set + * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and + * because we probably have padding left over), we convert any port to + * a uint16_t. + */ +struct http_parser_url { + uint16_t field_set; /* Bitmask of (1 << UF_*) values */ + uint16_t port; /* Converted UF_PORT string */ + + struct { + uint16_t off; /* Offset into buffer in which field starts */ + uint16_t len; /* Length of run in buffer */ + } field_data[UF_MAX]; +}; + + +void http_parser_init(http_parser *parser, enum http_parser_type type); + + +size_t http_parser_execute(http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len); + + +/* If http_should_keep_alive() in the on_headers_complete or + * on_message_complete callback returns true, then this will be should be + * the last message on the connection. + * If you are the server, respond with the "Connection: close" header. + * If you are the client, close the connection. + */ +int http_should_keep_alive(http_parser *parser); + +/* Returns a string version of the HTTP method. */ +const char *http_method_str(enum http_method m); + +/* Return a string name of the given error */ +const char *http_errno_name(enum http_errno err); + +/* Return a string description of the given error */ +const char *http_errno_description(enum http_errno err); + +/* Parse a URL; return nonzero on failure */ +int http_parser_parse_url(const char *buf, size_t buflen, + int is_connect, + struct http_parser_url *u); + +/* Pause or un-pause the parser; a nonzero value pauses */ +void http_parser_pause(http_parser *parser, int paused); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/test.c b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/test.c new file mode 100644 index 0000000..184ba24 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/ext/ruby_http_parser/vendor/http-parser/test.c @@ -0,0 +1,2876 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "http_parser.h" +#include +#include +#include +#include /* rand */ +#include +#include + +#undef TRUE +#define TRUE 1 +#undef FALSE +#define FALSE 0 + +#define MAX_HEADERS 13 +#define MAX_ELEMENT_SIZE 500 + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +static http_parser *parser; + +struct message { + const char *name; // for debugging purposes + const char *raw; + enum http_parser_type type; + enum http_method method; + int status_code; + char request_path[MAX_ELEMENT_SIZE]; + char request_url[MAX_ELEMENT_SIZE]; + char fragment[MAX_ELEMENT_SIZE]; + char query_string[MAX_ELEMENT_SIZE]; + char body[MAX_ELEMENT_SIZE]; + size_t body_size; + uint16_t port; + int num_headers; + enum { NONE=0, FIELD, VALUE } last_header_element; + char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; + int should_keep_alive; + + const char *upgrade; // upgraded body + + unsigned short http_major; + unsigned short http_minor; + + int message_begin_cb_called; + int headers_complete_cb_called; + int message_complete_cb_called; + int message_complete_on_eof; +}; + +static int currently_parsing_eof; + +static struct message messages[5]; +static int num_messages; +static http_parser_settings *current_pause_parser; + +/* * R E Q U E S T S * */ +const struct message requests[] = +#define CURL_GET 0 +{ {.name= "curl get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.1\r\n" + "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= + { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" } + , { "Host", "0.0.0.0=5000" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +#define FIREFOX_GET 1 +, {.name= "firefox get" + ,.type= HTTP_REQUEST + ,.raw= "GET /favicon.ico HTTP/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: en-us,en;q=0.5\r\n" + "Accept-Encoding: gzip,deflate\r\n" + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" + "Keep-Alive: 300\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/favicon.ico" + ,.request_url= "/favicon.ico" + ,.num_headers= 8 + ,.headers= + { { "Host", "0.0.0.0=5000" } + , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" } + , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" } + , { "Accept-Language", "en-us,en;q=0.5" } + , { "Accept-Encoding", "gzip,deflate" } + , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" } + , { "Keep-Alive", "300" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +#define DUMBFUCK 2 +, {.name= "dumbfuck" + ,.type= HTTP_REQUEST + ,.raw= "GET /dumbfuck HTTP/1.1\r\n" + "aaaaaaaaaaaaa:++++++++++\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/dumbfuck" + ,.request_url= "/dumbfuck" + ,.num_headers= 1 + ,.headers= + { { "aaaaaaaaaaaaa", "++++++++++" } + } + ,.body= "" + } + +#define FRAGMENT_IN_URI 3 +, {.name= "fragment in url" + ,.type= HTTP_REQUEST + ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "page=1" + ,.fragment= "posts-17408" + ,.request_path= "/forums/1/topics/2375" + /* XXX request url does include fragment? */ + ,.request_url= "/forums/1/topics/2375?page=1#posts-17408" + ,.num_headers= 0 + ,.body= "" + } + +#define GET_NO_HEADERS_NO_BODY 4 +, {.name= "get no headers no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_no_headers_no_body/world" + ,.request_url= "/get_no_headers_no_body/world" + ,.num_headers= 0 + ,.body= "" + } + +#define GET_ONE_HEADER_NO_BODY 5 +, {.name= "get one header no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_one_header_no_body" + ,.request_url= "/get_one_header_no_body" + ,.num_headers= 1 + ,.headers= + { { "Accept" , "*/*" } + } + ,.body= "" + } + +#define GET_FUNKY_CONTENT_LENGTH 6 +, {.name= "get funky content length body hello" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" + "conTENT-Length: 5\r\n" + "\r\n" + "HELLO" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_funky_content_length_body_hello" + ,.request_url= "/get_funky_content_length_body_hello" + ,.num_headers= 1 + ,.headers= + { { "conTENT-Length" , "5" } + } + ,.body= "HELLO" + } + +#define POST_IDENTITY_BODY_WORLD 7 +, {.name= "post identity body world" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" + "Accept: */*\r\n" + "Transfer-Encoding: identity\r\n" + "Content-Length: 5\r\n" + "\r\n" + "World" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "q=search" + ,.fragment= "hey" + ,.request_path= "/post_identity_body_world" + ,.request_url= "/post_identity_body_world?q=search#hey" + ,.num_headers= 3 + ,.headers= + { { "Accept", "*/*" } + , { "Transfer-Encoding", "identity" } + , { "Content-Length", "5" } + } + ,.body= "World" + } + +#define POST_CHUNKED_ALL_YOUR_BASE 8 +, {.name= "post - chunked body: all your base are belong to us" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "1e\r\nall your base are belong to us\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/post_chunked_all_your_base" + ,.request_url= "/post_chunked_all_your_base" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding" , "chunked" } + } + ,.body= "all your base are belong to us" + } + +#define TWO_CHUNKS_MULT_ZERO_END 9 +, {.name= "two chunks ; triple zero ending" + ,.type= HTTP_REQUEST + ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "000\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/two_chunks_mult_zero_end" + ,.request_url= "/two_chunks_mult_zero_end" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +#define CHUNKED_W_TRAILING_HEADERS 10 +, {.name= "chunked with trailing headers. blech." + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "0\r\n" + "Vary: *\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_trailing_headers" + ,.request_url= "/chunked_w_trailing_headers" + ,.num_headers= 3 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Vary", "*" } + , { "Content-Type", "text/plain" } + } + ,.body= "hello world" + } + +#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 +, {.name= "with bullshit after the length" + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n" + "6; blahblah; blah\r\n world\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_bullshit_after_length" + ,.request_url= "/chunked_w_bullshit_after_length" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +#define WITH_QUOTES 12 +, {.name= "with quotes" + ,.type= HTTP_REQUEST + ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "foo=\"bar\"" + ,.fragment= "" + ,.request_path= "/with_\"stupid\"_quotes" + ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\"" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define APACHEBENCH_GET 13 +/* The server receiving this request SHOULD NOT wait for EOF + * to know that content-length == 0. + * How to represent this in a unit test? message_complete_on_eof + * Compare with NO_CONTENT_LENGTH_RESPONSE. + */ +, {.name = "apachebench get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.0\r\n" + "Host: 0.0.0.0:5000\r\n" + "User-Agent: ApacheBench/2.3\r\n" + "Accept: */*\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= { { "Host", "0.0.0.0:5000" } + , { "User-Agent", "ApacheBench/2.3" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +#define QUERY_URL_WITH_QUESTION_MARK_GET 14 +/* Some clients include '?' characters in query strings. + */ +, {.name = "query url with question mark" + ,.type= HTTP_REQUEST + ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "foo=bar?baz" + ,.fragment= "" + ,.request_path= "/test.cgi" + ,.request_url= "/test.cgi?foo=bar?baz" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define PREFIX_NEWLINE_GET 15 +/* Some clients, especially after a POST in a keep-alive connection, + * will send an extra CRLF before the next request + */ +, {.name = "newline prefix get" + ,.type= HTTP_REQUEST + ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define UPGRADE_REQUEST 16 +, {.name = "upgrade request" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Upgrade: WebSocket\r\n" + "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" + "Origin: http://example.com\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 7 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Host", "example.com" } + , { "Connection", "Upgrade" } + , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" } + , { "Sec-WebSocket-Protocol", "sample" } + , { "Upgrade", "WebSocket" } + , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" } + , { "Origin", "http://example.com" } + } + ,.body= "" + } + +#define CONNECT_REQUEST 17 +, {.name = "connect request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + "some data\r\n" + "and yet even more data" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "0-home0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade="some data\r\nand yet even more data" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +#define REPORT_REQ 18 +, {.name= "report request" + ,.type= HTTP_REQUEST + ,.raw= "REPORT /test HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_REPORT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define NO_HTTP_VERSION 19 +, {.name= "request with no http version" + ,.type= HTTP_REQUEST + ,.raw= "GET /\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 0 + ,.http_minor= 9 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define MSEARCH_REQ 20 +, {.name= "m-search request" + ,.type= HTTP_REQUEST + ,.raw= "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "ST: \"ssdp:all\"\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_MSEARCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "*" + ,.request_url= "*" + ,.num_headers= 3 + ,.headers= { { "HOST", "239.255.255.250:1900" } + , { "MAN", "\"ssdp:discover\"" } + , { "ST", "\"ssdp:all\"" } + } + ,.body= "" + } + +#define LINE_FOLDING_IN_HEADER 20 +, {.name= "line folding in header value" + ,.type= HTTP_REQUEST + ,.raw= "GET / HTTP/1.1\r\n" + "Line1: abc\r\n" + "\tdef\r\n" + " ghi\r\n" + "\t\tjkl\r\n" + " mno \r\n" + "\t \tqrs\r\n" + "Line2: \t line2\t\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 2 + ,.headers= { { "Line1", "abcdefghijklmno qrs" } + , { "Line2", "line2\t" } + } + ,.body= "" + } + + +#define QUERY_TERMINATED_HOST 21 +, {.name= "host terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org?hail=all" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define QUERY_TERMINATED_HOSTPORT 22 +, {.name= "host:port terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234?hail=all" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define SPACE_TERMINATED_HOSTPORT 23 +, {.name= "host:port terminated by a space" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define PATCH_REQ 24 +, {.name = "PATCH request" + ,.type= HTTP_REQUEST + ,.raw= "PATCH /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/example\r\n" + "If-Match: \"e0023aa4e\"\r\n" + "Content-Length: 10\r\n" + "\r\n" + "cccccccccc" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PATCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 4 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/example" } + , { "If-Match", "\"e0023aa4e\"" } + , { "Content-Length", "10" } + } + ,.body= "cccccccccc" + } + +#define CONNECT_CAPS_REQUEST 25 +, {.name = "connect caps request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "HOME0.NETSCAPE.COM:443" + ,.num_headers= 2 + ,.upgrade="" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +#if !HTTP_PARSER_STRICT +#define UTF8_PATH_REQ 26 +, {.name= "utf-8 path request" + ,.type= HTTP_REQUEST + ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n" + "Host: github.com\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "q=1" + ,.fragment= "narf" + ,.request_path= "/δ¶/δt/pope" + ,.request_url= "/δ¶/δt/pope?q=1#narf" + ,.num_headers= 1 + ,.headers= { {"Host", "github.com" } + } + ,.body= "" + } + +#define HOSTNAME_UNDERSCORE 27 +, {.name = "hostname underscore" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "home_0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade="" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } +#endif /* !HTTP_PARSER_STRICT */ + +/* see https://github.com/ry/http-parser/issues/47 */ +#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 28 +, {.name = "eat CRLF between requests, no \"Connection: close\" header" + ,.raw= "POST / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 4\r\n" + "\r\n" + "q=42\r\n" /* note the trailing CRLF */ + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 3 + ,.upgrade= 0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/x-www-form-urlencoded" } + , { "Content-Length", "4" } + } + ,.body= "q=42" + } + +/* see https://github.com/ry/http-parser/issues/47 */ +#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 29 +, {.name = "eat CRLF between requests even if \"Connection: close\" is set" + ,.raw= "POST / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 4\r\n" + "Connection: close\r\n" + "\r\n" + "q=42\r\n" /* note the trailing CRLF */ + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 4 + ,.upgrade= 0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/x-www-form-urlencoded" } + , { "Content-Length", "4" } + , { "Connection", "close" } + } + ,.body= "q=42" + } + +#define PURGE_REQ 30 +, {.name = "PURGE request" + ,.type= HTTP_REQUEST + ,.raw= "PURGE /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PURGE + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 1 + ,.headers= { { "Host", "www.example.com" } } + ,.body= "" + } + +, {.name= NULL } /* sentinel */ +}; + +/* * R E S P O N S E S * */ +const struct message responses[] = +#define GOOGLE_301 0 +{ {.name= "google 301" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301 Moved Permanently\r\n" + "Location: http://www.google.com/\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n" + "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n" + "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */ + "Cache-Control: public, max-age=2592000\r\n" + "Server: gws\r\n" + "Content-Length: 219 \r\n" + "\r\n" + "\n" + "301 Moved\n" + "

    301 Moved

    \n" + "The document has moved\n" + "here.\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.num_headers= 8 + ,.headers= + { { "Location", "http://www.google.com/" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" } + , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" } + , { "X-$PrototypeBI-Version", "1.6.0.3" } + , { "Cache-Control", "public, max-age=2592000" } + , { "Server", "gws" } + , { "Content-Length", "219 " } + } + ,.body= "\n" + "301 Moved\n" + "

    301 Moved

    \n" + "The document has moved\n" + "here.\r\n" + "\r\n" + } + +#define NO_CONTENT_LENGTH_RESPONSE 1 +/* The client should wait for the server's EOF. That is, when content-length + * is not specified, and "Connection: close", the end of body is specified + * by the EOF. + * Compare with APACHEBENCH_GET + */ +, {.name= "no content-length response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" + "Server: Apache\r\n" + "X-Powered-By: Servlet/2.5 JSP/2.1\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" + "Connection: close\r\n" + "\r\n" + "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 5 + ,.headers= + { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" } + , { "Server", "Apache" } + , { "X-Powered-By", "Servlet/2.5 JSP/2.1" } + , { "Content-Type", "text/xml; charset=utf-8" } + , { "Connection", "close" } + } + ,.body= "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + } + +#define NO_HEADERS_NO_BODY_404 2 +, {.name= "404 no headers no body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 404 + ,.num_headers= 0 + ,.headers= {} + ,.body_size= 0 + ,.body= "" + } + +#define NO_REASON_PHRASE 3 +, {.name= "301 no response phrase" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301\r\n\r\n" + ,.should_keep_alive = FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +#define TRAILING_SPACE_ON_CHUNKED_BODY 4 +, {.name="200 trailing space on chunked body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "25 \r\n" + "This is the data in the first chunk\r\n" + "\r\n" + "1C\r\n" + "and this is the second one\r\n" + "\r\n" + "0 \r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/plain" } + , {"Transfer-Encoding", "chunked" } + } + ,.body_size = 37+28 + ,.body = + "This is the data in the first chunk\r\n" + "and this is the second one\r\n" + + } + +#define NO_CARRIAGE_RET 5 +, {.name="no carriage ret" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\n" + "Content-Type: text/html; charset=utf-8\n" + "Connection: close\n" + "\n" + "these headers are from http://news.ycombinator.com/" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/html; charset=utf-8" } + , {"Connection", "close" } + } + ,.body= "these headers are from http://news.ycombinator.com/" + } + +#define PROXY_CONNECTION 6 +, {.name="proxy connection" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Content-Length: 11\r\n" + "Proxy-Connection: close\r\n" + "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 4 + ,.headers= + { {"Content-Type", "text/html; charset=UTF-8" } + , {"Content-Length", "11" } + , {"Proxy-Connection", "close" } + , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"} + } + ,.body= "hello world" + } + +#define UNDERSTORE_HEADER_KEY 7 + // shown by + // curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;" +, {.name="underscore header key" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Server: DCLK-AdSvr\r\n" + "Content-Type: text/xml\r\n" + "Content-Length: 0\r\n" + "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 4 + ,.headers= + { {"Server", "DCLK-AdSvr" } + , {"Content-Type", "text/xml" } + , {"Content-Length", "0" } + , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" } + } + ,.body= "" + } + +#define BONJOUR_MADAME_FR 8 +/* The client should not merge two headers fields when the first one doesn't + * have a value. + */ +, {.name= "bonjourmadame.fr" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 301 Moved Permanently\r\n" + "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n" + "Server: Apache/2.2.3 (Red Hat)\r\n" + "Cache-Control: public\r\n" + "Pragma: \r\n" + "Location: http://www.bonjourmadame.fr/\r\n" + "Vary: Accept-Encoding\r\n" + "Content-Length: 0\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 301 + ,.num_headers= 9 + ,.headers= + { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" } + , { "Server", "Apache/2.2.3 (Red Hat)" } + , { "Cache-Control", "public" } + , { "Pragma", "" } + , { "Location", "http://www.bonjourmadame.fr/" } + , { "Vary", "Accept-Encoding" } + , { "Content-Length", "0" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +#define RES_FIELD_UNDERSCORE 9 +/* Should handle spaces in header fields */ +, {.name= "field underscore" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n" + "Server: Apache\r\n" + "Cache-Control: no-cache, must-revalidate\r\n" + "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" + ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n" + "Vary: Accept-Encoding\r\n" + "_eep-Alive: timeout=45\r\n" /* semantic value ignored */ + "_onnection: Keep-Alive\r\n" /* semantic value ignored */ + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "0\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 11 + ,.headers= + { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" } + , { "Server", "Apache" } + , { "Cache-Control", "no-cache, must-revalidate" } + , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" } + , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" } + , { "Vary", "Accept-Encoding" } + , { "_eep-Alive", "timeout=45" } + , { "_onnection", "Keep-Alive" } + , { "Transfer-Encoding", "chunked" } + , { "Content-Type", "text/html" } + , { "Connection", "close" } + } + ,.body= "" + } + +#define NON_ASCII_IN_STATUS_LINE 10 +/* Should handle non-ASCII in status line */ +, {.name= "non-ASCII in status line" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n" + "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 500 + ,.num_headers= 3 + ,.headers= + { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" } + , { "Content-Length", "0" } + , { "Connection", "close" } + } + ,.body= "" + } + +#define HTTP_VERSION_0_9 11 +/* Should handle HTTP/0.9 */ +, {.name= "http version 0.9" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/0.9 200 OK\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 0 + ,.http_minor= 9 + ,.status_code= 200 + ,.num_headers= 0 + ,.headers= + {} + ,.body= "" + } + +#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12 +/* The client should wait for the server's EOF. That is, when neither + * content-length nor transfer-encoding is specified, the end of body + * is specified by the EOF. + */ +, {.name= "neither content-length nor transfer-encoding response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Content-Type", "text/plain" } + } + ,.body= "hello world" + } + +#define NO_BODY_HTTP10_KA_200 13 +, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 200 OK\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Connection", "keep-alive" } + } + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP10_KA_204 14 +, {.name= "HTTP/1.0 with keep-alive and a 204 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 204 No content\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 204 + ,.num_headers= 1 + ,.headers= + { { "Connection", "keep-alive" } + } + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_KA_200 15 +, {.name= "HTTP/1.1 with an EOF-terminated 200 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 0 + ,.headers={} + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_KA_204 16 +, {.name= "HTTP/1.1 with a 204 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No content\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.num_headers= 0 + ,.headers={} + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_NOKA_204 17 +, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No content\r\n" + "Connection: close\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.num_headers= 1 + ,.headers= + { { "Connection", "close" } + } + ,.body_size= 0 + ,.body= "" + } + +#define NO_BODY_HTTP11_KA_CHUNKED_200 18 +, {.name= "HTTP/1.1 with chunked endocing and a 200 response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body_size= 0 + ,.body= "" + } + +#if !HTTP_PARSER_STRICT +#define SPACE_IN_FIELD_RES 19 +/* Should handle spaces in header fields */ +, {.name= "field space" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Server: Microsoft-IIS/6.0\r\n" + "X-Powered-By: ASP.NET\r\n" + "en-US Content-Type: text/xml\r\n" /* this is the problem */ + "Content-Type: text/xml\r\n" + "Content-Length: 16\r\n" + "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "hello" /* fake body */ + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 7 + ,.headers= + { { "Server", "Microsoft-IIS/6.0" } + , { "X-Powered-By", "ASP.NET" } + , { "en-US Content-Type", "text/xml" } + , { "Content-Type", "text/xml" } + , { "Content-Length", "16" } + , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" } + , { "Connection", "keep-alive" } + } + ,.body= "hello" + } +#endif /* !HTTP_PARSER_STRICT */ + +, {.name= NULL } /* sentinel */ +}; + +int +request_url_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + strncat(messages[num_messages].request_url, buf, len); + return 0; +} + +int +header_field_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + struct message *m = &messages[num_messages]; + + if (m->last_header_element != FIELD) + m->num_headers++; + + strncat(m->headers[m->num_headers-1][0], buf, len); + + m->last_header_element = FIELD; + + return 0; +} + +int +header_value_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + struct message *m = &messages[num_messages]; + + strncat(m->headers[m->num_headers-1][1], buf, len); + + m->last_header_element = VALUE; + + return 0; +} + +int +body_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + strncat(messages[num_messages].body, buf, len); + messages[num_messages].body_size += len; + // printf("body_cb: '%s'\n", requests[num_messages].body); + return 0; +} + +int +count_body_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + assert(buf); + messages[num_messages].body_size += len; + return 0; +} + +int +message_begin_cb (http_parser *p) +{ + assert(p == parser); + messages[num_messages].message_begin_cb_called = TRUE; + return 0; +} + +int +headers_complete_cb (http_parser *p) +{ + assert(p == parser); + messages[num_messages].method = parser->method; + messages[num_messages].status_code = parser->status_code; + messages[num_messages].http_major = parser->http_major; + messages[num_messages].http_minor = parser->http_minor; + messages[num_messages].headers_complete_cb_called = TRUE; + messages[num_messages].should_keep_alive = http_should_keep_alive(parser); + return 0; +} + +int +message_complete_cb (http_parser *p) +{ + assert(p == parser); + if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser)) + { + fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same " + "value in both on_message_complete and on_headers_complete " + "but it doesn't! ***\n\n"); + assert(0); + exit(1); + } + messages[num_messages].message_complete_cb_called = TRUE; + + messages[num_messages].message_complete_on_eof = currently_parsing_eof; + + num_messages++; + return 0; +} + +/* These dontcall_* callbacks exist so that we can verify that when we're + * paused, no additional callbacks are invoked */ +int +dontcall_message_begin_cb (http_parser *p) +{ + if (p) { } // gcc + fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n"); + exit(1); +} + +int +dontcall_header_field_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n"); + exit(1); +} + +int +dontcall_header_value_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n"); + exit(1); +} + +int +dontcall_request_url_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n"); + exit(1); +} + +int +dontcall_body_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n"); + exit(1); +} + +int +dontcall_headers_complete_cb (http_parser *p) +{ + if (p) { } // gcc + fprintf(stderr, "\n\n*** on_headers_complete() called on paused " + "parser ***\n\n"); + exit(1); +} + +int +dontcall_message_complete_cb (http_parser *p) +{ + if (p) { } // gcc + fprintf(stderr, "\n\n*** on_message_complete() called on paused " + "parser ***\n\n"); + exit(1); +} + +static http_parser_settings settings_dontcall = + {.on_message_begin = dontcall_message_begin_cb + ,.on_header_field = dontcall_header_field_cb + ,.on_header_value = dontcall_header_value_cb + ,.on_url = dontcall_request_url_cb + ,.on_body = dontcall_body_cb + ,.on_headers_complete = dontcall_headers_complete_cb + ,.on_message_complete = dontcall_message_complete_cb + }; + +/* These pause_* callbacks always pause the parser and just invoke the regular + * callback that tracks content. Before returning, we overwrite the parser + * settings to point to the _dontcall variety so that we can verify that + * the pause actually did, you know, pause. */ +int +pause_message_begin_cb (http_parser *p) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return message_begin_cb(p); +} + +int +pause_header_field_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return header_field_cb(p, buf, len); +} + +int +pause_header_value_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return header_value_cb(p, buf, len); +} + +int +pause_request_url_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return request_url_cb(p, buf, len); +} + +int +pause_body_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return body_cb(p, buf, len); +} + +int +pause_headers_complete_cb (http_parser *p) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return headers_complete_cb(p); +} + +int +pause_message_complete_cb (http_parser *p) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return message_complete_cb(p); +} + +static http_parser_settings settings_pause = + {.on_message_begin = pause_message_begin_cb + ,.on_header_field = pause_header_field_cb + ,.on_header_value = pause_header_value_cb + ,.on_url = pause_request_url_cb + ,.on_body = pause_body_cb + ,.on_headers_complete = pause_headers_complete_cb + ,.on_message_complete = pause_message_complete_cb + }; + +static http_parser_settings settings = + {.on_message_begin = message_begin_cb + ,.on_header_field = header_field_cb + ,.on_header_value = header_value_cb + ,.on_url = request_url_cb + ,.on_body = body_cb + ,.on_headers_complete = headers_complete_cb + ,.on_message_complete = message_complete_cb + }; + +static http_parser_settings settings_count_body = + {.on_message_begin = message_begin_cb + ,.on_header_field = header_field_cb + ,.on_header_value = header_value_cb + ,.on_url = request_url_cb + ,.on_body = count_body_cb + ,.on_headers_complete = headers_complete_cb + ,.on_message_complete = message_complete_cb + }; + +static http_parser_settings settings_null = + {.on_message_begin = 0 + ,.on_header_field = 0 + ,.on_header_value = 0 + ,.on_url = 0 + ,.on_body = 0 + ,.on_headers_complete = 0 + ,.on_message_complete = 0 + }; + +void +parser_init (enum http_parser_type type) +{ + num_messages = 0; + + assert(parser == NULL); + + parser = malloc(sizeof(http_parser)); + + http_parser_init(parser, type); + + memset(&messages, 0, sizeof messages); + +} + +void +parser_free () +{ + assert(parser); + free(parser); + parser = NULL; +} + +size_t parse (const char *buf, size_t len) +{ + size_t nparsed; + currently_parsing_eof = (len == 0); + nparsed = http_parser_execute(parser, &settings, buf, len); + return nparsed; +} + +size_t parse_count_body (const char *buf, size_t len) +{ + size_t nparsed; + currently_parsing_eof = (len == 0); + nparsed = http_parser_execute(parser, &settings_count_body, buf, len); + return nparsed; +} + +size_t parse_pause (const char *buf, size_t len) +{ + size_t nparsed; + http_parser_settings s = settings_pause; + + currently_parsing_eof = (len == 0); + current_pause_parser = &s; + nparsed = http_parser_execute(parser, current_pause_parser, buf, len); + return nparsed; +} + +static inline int +check_str_eq (const struct message *m, + const char *prop, + const char *expected, + const char *found) { + if ((expected == NULL) != (found == NULL)) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %s\n", (expected == NULL) ? "NULL" : expected); + printf(" found %s\n", (found == NULL) ? "NULL" : found); + return 0; + } + if (expected != NULL && 0 != strcmp(expected, found)) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected '%s'\n", expected); + printf(" found '%s'\n", found); + return 0; + } + return 1; +} + +static inline int +check_num_eq (const struct message *m, + const char *prop, + int expected, + int found) { + if (expected != found) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %d\n", expected); + printf(" found %d\n", found); + return 0; + } + return 1; +} + +#define MESSAGE_CHECK_STR_EQ(expected, found, prop) \ + if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \ + if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \ +do { \ + char ubuf[256]; \ + \ + if ((u)->field_set & (1 << (fn))) { \ + memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \ + (u)->field_data[(fn)].len); \ + ubuf[(u)->field_data[(fn)].len] = '\0'; \ + } else { \ + ubuf[0] = '\0'; \ + } \ + \ + check_str_eq(expected, #prop, expected->prop, ubuf); \ +} while(0) + +int +message_eq (int index, const struct message *expected) +{ + int i; + struct message *m = &messages[index]; + + MESSAGE_CHECK_NUM_EQ(expected, m, http_major); + MESSAGE_CHECK_NUM_EQ(expected, m, http_minor); + + if (expected->type == HTTP_REQUEST) { + MESSAGE_CHECK_NUM_EQ(expected, m, method); + } else { + MESSAGE_CHECK_NUM_EQ(expected, m, status_code); + } + + MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); + MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); + + assert(m->message_begin_cb_called); + assert(m->headers_complete_cb_called); + assert(m->message_complete_cb_called); + + + MESSAGE_CHECK_STR_EQ(expected, m, request_url); + + /* Check URL components; we can't do this w/ CONNECT since it doesn't + * send us a well-formed URL. + */ + if (*m->request_url && m->method != HTTP_CONNECT) { + struct http_parser_url u; + + if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) { + fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n", + m->request_url); + exit(1); + } + + m->port = (u.field_set & (1 << UF_PORT)) ? + u.port : 0; + + MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY); + MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT); + MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH); + MESSAGE_CHECK_NUM_EQ(expected, m, port); + } + + if (expected->body_size) { + MESSAGE_CHECK_NUM_EQ(expected, m, body_size); + } else { + MESSAGE_CHECK_STR_EQ(expected, m, body); + } + + MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); + + int r; + for (i = 0; i < m->num_headers; i++) { + r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]); + if (!r) return 0; + r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]); + if (!r) return 0; + } + + MESSAGE_CHECK_STR_EQ(expected, m, upgrade); + + return 1; +} + +/* Given a sequence of varargs messages, return the number of them that the + * parser should successfully parse, taking into account that upgraded + * messages prevent all subsequent messages from being parsed. + */ +size_t +count_parsed_messages(const size_t nmsgs, ...) { + size_t i; + va_list ap; + + va_start(ap, nmsgs); + + for (i = 0; i < nmsgs; i++) { + struct message *m = va_arg(ap, struct message *); + + if (m->upgrade) { + va_end(ap); + return i + 1; + } + } + + va_end(ap); + return nmsgs; +} + +/* Given a sequence of bytes and the number of these that we were able to + * parse, verify that upgrade bodies are correct. + */ +void +upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) { + va_list ap; + size_t i; + size_t off = 0; + + va_start(ap, nmsgs); + + for (i = 0; i < nmsgs; i++) { + struct message *m = va_arg(ap, struct message *); + + off += strlen(m->raw); + + if (m->upgrade) { + off -= strlen(m->upgrade); + + /* Check the portion of the response after its specified upgrade */ + if (!check_str_eq(m, "upgrade", body + off, body + nread)) { + exit(1); + } + + /* Fix up the response so that message_eq() will verify the beginning + * of the upgrade */ + *(body + nread + strlen(m->upgrade)) = '\0'; + messages[num_messages -1 ].upgrade = body + nread; + + va_end(ap); + return; + } + } + + va_end(ap); + printf("\n\n*** Error: expected a message with upgrade ***\n"); + + exit(1); +} + +static void +print_error (const char *raw, size_t error_location) +{ + fprintf(stderr, "\n*** %s:%d -- %s ***\n\n", + "http_parser.c", HTTP_PARSER_ERRNO_LINE(parser), + http_errno_description(HTTP_PARSER_ERRNO(parser))); + + int this_line = 0, char_len = 0; + size_t i, j, len = strlen(raw), error_location_line = 0; + for (i = 0; i < len; i++) { + if (i == error_location) this_line = 1; + switch (raw[i]) { + case '\r': + char_len = 2; + fprintf(stderr, "\\r"); + break; + + case '\n': + char_len = 2; + fprintf(stderr, "\\n\n"); + + if (this_line) goto print; + + error_location_line = 0; + continue; + + default: + char_len = 1; + fputc(raw[i], stderr); + break; + } + if (!this_line) error_location_line += char_len; + } + + fprintf(stderr, "[eof]\n"); + + print: + for (j = 0; j < error_location_line; j++) { + fputc(' ', stderr); + } + fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location); +} + +void +test_preserve_data (void) +{ + char my_data[] = "application-specific data"; + http_parser parser; + parser.data = my_data; + http_parser_init(&parser, HTTP_REQUEST); + if (parser.data != my_data) { + printf("\n*** parser.data not preserved accross http_parser_init ***\n\n"); + exit(1); + } +} + +struct url_test { + const char *name; + const char *url; + int is_connect; + struct http_parser_url u; + int rv; +}; + +const struct url_test url_tests[] = +{ {.name="proxy request" + ,.url="http://hostname/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 7, 8 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 15, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + +, {.name="CONNECT request" + ,.url="hostname:443" + ,.is_connect=1 + ,.u= + {.field_set=(1 << UF_HOST) | (1 << UF_PORT) + ,.port=443 + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 0, 8 } /* UF_HOST */ + ,{ 9, 3 } /* UF_PORT */ + ,{ 0, 0 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + +, {.name="proxy ipv6 request" + ,.url="http://[1:2::3:4]/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 8 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 17, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + +, {.name="CONNECT ipv6 address" + ,.url="[1:2::3:4]:443" + ,.is_connect=1 + ,.u= + {.field_set=(1 << UF_HOST) | (1 << UF_PORT) + ,.port=443 + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 1, 8 } /* UF_HOST */ + ,{ 11, 3 } /* UF_PORT */ + ,{ 0, 0 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + +, {.name="extra ? in query string" + ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css" + ,.is_connect=0 + ,.u= + {.field_set=(1<field_set, u->port); + for (i = 0; i < UF_MAX; i++) { + if ((u->field_set & (1 << i)) == 0) { + printf("\tfield_data[%u]: unset\n", i); + continue; + } + + memcpy(part, url + u->field_data[i].off, u->field_data[i].len); + part[u->field_data[i].len] = '\0'; + + printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n", + i, + u->field_data[i].off, + u->field_data[i].len, + part); + } +} + +void +test_parse_url (void) +{ + struct http_parser_url u; + const struct url_test *test; + unsigned int i; + int rv; + + for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) { + test = &url_tests[i]; + memset(&u, 0, sizeof(u)); + + rv = http_parser_parse_url(test->url, + strlen(test->url), + test->is_connect, + &u); + + if (test->rv == 0) { + if (rv != 0) { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " + "unexpected rv %d ***\n\n", test->url, test->name, rv); + exit(1); + } + + if (memcmp(&u, &test->u, sizeof(u)) != 0) { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n", + test->url, test->name); + + printf("target http_parser_url:\n"); + dump_url(test->url, &test->u); + printf("result http_parser_url:\n"); + dump_url(test->url, &u); + + exit(1); + } + } else { + /* test->rv != 0 */ + if (rv == 0) { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " + "unexpected rv %d ***\n\n", test->url, test->name, rv); + exit(1); + } + } + } +} + +void +test_message (const struct message *message) +{ + size_t raw_len = strlen(message->raw); + size_t msg1len; + for (msg1len = 0; msg1len < raw_len; msg1len++) { + parser_init(message->type); + + size_t read; + const char *msg1 = message->raw; + const char *msg2 = msg1 + msg1len; + size_t msg2len = raw_len - msg1len; + + if (msg1len) { + read = parse(msg1, msg1len); + + if (message->upgrade && parser->upgrade) { + messages[num_messages - 1].upgrade = msg1 + read; + goto test; + } + + if (read != msg1len) { + print_error(msg1, read); + exit(1); + } + } + + + read = parse(msg2, msg2len); + + if (message->upgrade && parser->upgrade) { + messages[num_messages - 1].upgrade = msg2 + read; + goto test; + } + + if (read != msg2len) { + print_error(msg2, read); + exit(1); + } + + read = parse(NULL, 0); + + if (read != 0) { + print_error(message->raw, read); + exit(1); + } + + test: + + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + exit(1); + } + + if(!message_eq(0, message)) exit(1); + + parser_free(); + } +} + +void +test_message_count_body (const struct message *message) +{ + parser_init(message->type); + + size_t read; + size_t l = strlen(message->raw); + size_t i, toread; + size_t chunk = 4024; + + for (i = 0; i < l; i+= chunk) { + toread = MIN(l-i, chunk); + read = parse_count_body(message->raw + i, toread); + if (read != toread) { + print_error(message->raw, read); + exit(1); + } + } + + + read = parse_count_body(NULL, 0); + if (read != 0) { + print_error(message->raw, read); + exit(1); + } + + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + exit(1); + } + + if(!message_eq(0, message)) exit(1); + + parser_free(); +} + +void +test_simple (const char *buf, enum http_errno err_expected) +{ + parser_init(HTTP_REQUEST); + + size_t parsed; + int pass; + enum http_errno err; + + parsed = parse(buf, strlen(buf)); + pass = (parsed == strlen(buf)); + err = HTTP_PARSER_ERRNO(parser); + parsed = parse(NULL, 0); + pass &= (parsed == 0); + + parser_free(); + + /* In strict mode, allow us to pass with an unexpected HPE_STRICT as + * long as the caller isn't expecting success. + */ +#if HTTP_PARSER_STRICT + if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) { +#else + if (err_expected != err) { +#endif + fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n", + http_errno_name(err_expected), http_errno_name(err), buf); + exit(1); + } +} + +void +test_header_overflow_error (int req) +{ + http_parser parser; + http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE); + size_t parsed; + const char *buf; + buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n"; + parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf)); + assert(parsed == strlen(buf)); + + buf = "header-key: header-value\r\n"; + size_t buflen = strlen(buf); + + int i; + for (i = 0; i < 10000; i++) { + parsed = http_parser_execute(&parser, &settings_null, buf, buflen); + if (parsed != buflen) { + //fprintf(stderr, "error found on iter %d\n", i); + assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW); + return; + } + } + + fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n"); + exit(1); +} + +static void +test_content_length_overflow (const char *buf, size_t buflen, int expect_ok) +{ + http_parser parser; + http_parser_init(&parser, HTTP_RESPONSE); + http_parser_execute(&parser, &settings_null, buf, buflen); + + if (expect_ok) + assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK); + else + assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH); +} + +void +test_header_content_length_overflow_error (void) +{ +#define X(size) \ + "HTTP/1.1 200 OK\r\n" \ + "Content-Length: " #size "\r\n" \ + "\r\n" + const char a[] = X(18446744073709551614); /* 2^64-2 */ + const char b[] = X(18446744073709551615); /* 2^64-1 */ + const char c[] = X(18446744073709551616); /* 2^64 */ +#undef X + test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */ + test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */ + test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */ +} + +void +test_chunk_content_length_overflow_error (void) +{ +#define X(size) \ + "HTTP/1.1 200 OK\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "\r\n" \ + #size "\r\n" \ + "..." + const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */ + const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */ + const char c[] = X(10000000000000000); /* 2^64 */ +#undef X + test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */ + test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */ + test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */ +} + +void +test_no_overflow_long_body (int req, size_t length) +{ + http_parser parser; + http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE); + size_t parsed; + size_t i; + char buf1[3000]; + size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %zu\r\n\r\n", + req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", length); + parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len); + if (parsed != buf1len) + goto err; + + for (i = 0; i < length; i++) { + char foo = 'a'; + parsed = http_parser_execute(&parser, &settings_null, &foo, 1); + if (parsed != 1) + goto err; + } + + parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len); + if (parsed != buf1len) goto err; + return; + + err: + fprintf(stderr, + "\n*** error in test_no_overflow_long_body %s of length %zu ***\n", + req ? "REQUEST" : "RESPONSE", + length); + exit(1); +} + +void +test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3) +{ + int message_count = count_parsed_messages(3, r1, r2, r3); + + char total[ strlen(r1->raw) + + strlen(r2->raw) + + strlen(r3->raw) + + 1 + ]; + total[0] = '\0'; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + parser_init(r1->type); + + size_t read; + + read = parse(total, strlen(total)); + + if (parser->upgrade) { + upgrade_message_fix(total, read, 3, r1, r2, r3); + goto test; + } + + if (read != strlen(total)) { + print_error(total, read); + exit(1); + } + + read = parse(NULL, 0); + + if (read != 0) { + print_error(total, read); + exit(1); + } + +test: + + if (message_count != num_messages) { + fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages); + exit(1); + } + + if (!message_eq(0, r1)) exit(1); + if (message_count > 1 && !message_eq(1, r2)) exit(1); + if (message_count > 2 && !message_eq(2, r3)) exit(1); + + parser_free(); +} + +/* SCAN through every possible breaking to make sure the + * parser can handle getting the content in any chunks that + * might come from the socket + */ +void +test_scan (const struct message *r1, const struct message *r2, const struct message *r3) +{ + char total[80*1024] = "\0"; + char buf1[80*1024] = "\0"; + char buf2[80*1024] = "\0"; + char buf3[80*1024] = "\0"; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + size_t read; + + int total_len = strlen(total); + + int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2; + int ops = 0 ; + + size_t buf1_len, buf2_len, buf3_len; + int message_count = count_parsed_messages(3, r1, r2, r3); + + int i,j,type_both; + for (type_both = 0; type_both < 2; type_both ++ ) { + for (j = 2; j < total_len; j ++ ) { + for (i = 1; i < j; i ++ ) { + + if (ops % 1000 == 0) { + printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops); + fflush(stdout); + } + ops += 1; + + parser_init(type_both ? HTTP_BOTH : r1->type); + + buf1_len = i; + strncpy(buf1, total, buf1_len); + buf1[buf1_len] = 0; + + buf2_len = j - i; + strncpy(buf2, total+i, buf2_len); + buf2[buf2_len] = 0; + + buf3_len = total_len - j; + strncpy(buf3, total+j, buf3_len); + buf3[buf3_len] = 0; + + read = parse(buf1, buf1_len); + + if (parser->upgrade) goto test; + + if (read != buf1_len) { + print_error(buf1, read); + goto error; + } + + read += parse(buf2, buf2_len); + + if (parser->upgrade) goto test; + + if (read != buf1_len + buf2_len) { + print_error(buf2, read); + goto error; + } + + read += parse(buf3, buf3_len); + + if (parser->upgrade) goto test; + + if (read != buf1_len + buf2_len + buf3_len) { + print_error(buf3, read); + goto error; + } + + parse(NULL, 0); + +test: + if (parser->upgrade) { + upgrade_message_fix(total, read, 3, r1, r2, r3); + } + + if (message_count != num_messages) { + fprintf(stderr, "\n\nParser didn't see %d messages only %d\n", + message_count, num_messages); + goto error; + } + + if (!message_eq(0, r1)) { + fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); + goto error; + } + + if (message_count > 1 && !message_eq(1, r2)) { + fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); + goto error; + } + + if (message_count > 2 && !message_eq(2, r3)) { + fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); + goto error; + } + + parser_free(); + } + } + } + puts("\b\b\b\b100%"); + return; + + error: + fprintf(stderr, "i=%d j=%d\n", i, j); + fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1); + fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2); + fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3); + exit(1); +} + +// user required to free the result +// string terminated by \0 +char * +create_large_chunked_message (int body_size_in_kb, const char* headers) +{ + int i; + size_t wrote = 0; + size_t headers_len = strlen(headers); + size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6; + char * buf = malloc(bufsize); + + memcpy(buf, headers, headers_len); + wrote += headers_len; + + for (i = 0; i < body_size_in_kb; i++) { + // write 1kb chunk into the body. + memcpy(buf + wrote, "400\r\n", 5); + wrote += 5; + memset(buf + wrote, 'C', 1024); + wrote += 1024; + strcpy(buf + wrote, "\r\n"); + wrote += 2; + } + + memcpy(buf + wrote, "0\r\n\r\n", 6); + wrote += 6; + assert(wrote == bufsize); + + return buf; +} + +/* Verify that we can pause parsing at any of the bytes in the + * message and still get the result that we're expecting. */ +void +test_message_pause (const struct message *msg) +{ + char *buf = (char*) msg->raw; + size_t buflen = strlen(msg->raw); + size_t nread; + + parser_init(msg->type); + + do { + nread = parse_pause(buf, buflen); + + // We can only set the upgrade buffer once we've gotten our message + // completion callback. + if (messages[0].message_complete_cb_called && + msg->upgrade && + parser->upgrade) { + messages[0].upgrade = buf + nread; + goto test; + } + + if (nread < buflen) { + + // Not much do to if we failed a strict-mode check + if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) { + parser_free(); + return; + } + + assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED); + } + + buf += nread; + buflen -= nread; + http_parser_pause(parser, 0); + } while (buflen > 0); + + nread = parse_pause(NULL, 0); + assert (nread == 0); + +test: + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name); + exit(1); + } + + if(!message_eq(0, msg)) exit(1); + + parser_free(); +} + +int +main (void) +{ + parser = NULL; + int i, j, k; + int request_count; + int response_count; + + printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser)); + + for (request_count = 0; requests[request_count].name; request_count++); + for (response_count = 0; responses[response_count].name; response_count++); + + //// API + test_preserve_data(); + test_parse_url(); + + //// OVERFLOW CONDITIONS + + test_header_overflow_error(HTTP_REQUEST); + test_no_overflow_long_body(HTTP_REQUEST, 1000); + test_no_overflow_long_body(HTTP_REQUEST, 100000); + + test_header_overflow_error(HTTP_RESPONSE); + test_no_overflow_long_body(HTTP_RESPONSE, 1000); + test_no_overflow_long_body(HTTP_RESPONSE, 100000); + + test_header_content_length_overflow_error(); + test_chunk_content_length_overflow_error(); + + //// RESPONSES + + for (i = 0; i < response_count; i++) { + test_message(&responses[i]); + } + + for (i = 0; i < response_count; i++) { + test_message_pause(&responses[i]); + } + + for (i = 0; i < response_count; i++) { + if (!responses[i].should_keep_alive) continue; + for (j = 0; j < response_count; j++) { + if (!responses[j].should_keep_alive) continue; + for (k = 0; k < response_count; k++) { + test_multiple3(&responses[i], &responses[j], &responses[k]); + } + } + } + + test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]); + test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]); + + // test very large chunked response + { + char * msg = create_large_chunked_message(31337, + "HTTP/1.0 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/plain\r\n" + "\r\n"); + struct message large_chunked = + {.name= "large chunked" + ,.type= HTTP_RESPONSE + ,.raw= msg + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Content-Type", "text/plain" } + } + ,.body_size= 31337*1024 + }; + test_message_count_body(&large_chunked); + free(msg); + } + + + + printf("response scan 1/2 "); + test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY] + , &responses[NO_BODY_HTTP10_KA_204] + , &responses[NO_REASON_PHRASE] + ); + + printf("response scan 2/2 "); + test_scan( &responses[BONJOUR_MADAME_FR] + , &responses[UNDERSTORE_HEADER_KEY] + , &responses[NO_CARRIAGE_RET] + ); + + puts("responses okay"); + + + /// REQUESTS + + test_simple("hello world", HPE_INVALID_METHOD); + test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION); + + + test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD); + test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD); + test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD); + + // Well-formed but incomplete + test_simple("GET / HTTP/1.1\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 6\r\n" + "\r\n" + "fooba", + HPE_OK); + + static const char *all_methods[] = { + "DELETE", + "GET", + "HEAD", + "POST", + "PUT", + //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel + "OPTIONS", + "TRACE", + "COPY", + "LOCK", + "MKCOL", + "MOVE", + "PROPFIND", + "PROPPATCH", + "UNLOCK", + "REPORT", + "MKACTIVITY", + "CHECKOUT", + "MERGE", + "M-SEARCH", + "NOTIFY", + "SUBSCRIBE", + "UNSUBSCRIBE", + "PATCH", + 0 }; + const char **this_method; + for (this_method = all_methods; *this_method; this_method++) { + char buf[200]; + sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); + test_simple(buf, HPE_OK); + } + + static const char *bad_methods[] = { + "C******", + "M****", + 0 }; + for (this_method = bad_methods; *this_method; this_method++) { + char buf[200]; + sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); + test_simple(buf, HPE_UNKNOWN); + } + + const char *dumbfuck2 = + "GET / HTTP/1.1\r\n" + "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n" + "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n" + "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n" + "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n" + "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n" + "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n" + "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n" + "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n" + "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n" + "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n" + "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n" + "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n" + "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n" + "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n" + "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n" + "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n" + "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n" + "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n" + "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n" + "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n" + "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n" + "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n" + "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n" + "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n" + "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n" + "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n" + "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n" + "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n" + "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n" + "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n" + "\tRA==\r\n" + "\t-----END CERTIFICATE-----\r\n" + "\r\n"; + test_simple(dumbfuck2, HPE_OK); + +#if 0 + // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body + // until EOF. + // + // no content-length + // error if there is a body without content length + const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + "HELLO"; + test_simple(bad_get_no_headers_no_body, 0); +#endif + /* TODO sending junk and large headers gets rejected */ + + + /* check to make sure our predefined requests are okay */ + for (i = 0; requests[i].name; i++) { + test_message(&requests[i]); + } + + for (i = 0; i < request_count; i++) { + test_message_pause(&requests[i]); + } + + for (i = 0; i < request_count; i++) { + if (!requests[i].should_keep_alive) continue; + for (j = 0; j < request_count; j++) { + if (!requests[j].should_keep_alive) continue; + for (k = 0; k < request_count; k++) { + test_multiple3(&requests[i], &requests[j], &requests[k]); + } + } + } + + printf("request scan 1/4 "); + test_scan( &requests[GET_NO_HEADERS_NO_BODY] + , &requests[GET_ONE_HEADER_NO_BODY] + , &requests[GET_NO_HEADERS_NO_BODY] + ); + + printf("request scan 2/4 "); + test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE] + , &requests[POST_IDENTITY_BODY_WORLD] + , &requests[GET_FUNKY_CONTENT_LENGTH] + ); + + printf("request scan 3/4 "); + test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END] + , &requests[CHUNKED_W_TRAILING_HEADERS] + , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH] + ); + + printf("request scan 4/4 "); + test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET] + , &requests[PREFIX_NEWLINE_GET ] + , &requests[CONNECT_REQUEST] + ); + + puts("requests okay"); + + return 0; +} diff --git a/.gems/gems/http_parser.rb-0.6.0/http_parser.rb.gemspec b/.gems/gems/http_parser.rb-0.6.0/http_parser.rb.gemspec new file mode 100644 index 0000000..9a406f8 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/http_parser.rb.gemspec @@ -0,0 +1,28 @@ +Gem::Specification.new do |s| + s.name = "http_parser.rb" + s.version = "0.6.0" + s.summary = "Simple callback-based HTTP request/response parser" + s.description = "Ruby bindings to http://github.com/ry/http-parser and http://github.com/a2800276/http-parser.java" + + s.authors = ["Marc-Andre Cournoyer", "Aman Gupta"] + s.email = ["macournoyer@gmail.com", "aman@tmm1.net"] + s.license = 'MIT' + + s.homepage = "http://github.com/tmm1/http_parser.rb" + s.files = `git ls-files`.split("\n") + Dir['ext/ruby_http_parser/vendor/**/*'] + + s.require_paths = ["lib"] + s.extensions = ["ext/ruby_http_parser/extconf.rb"] + + s.add_development_dependency 'rake-compiler', '>= 0.7.9' + s.add_development_dependency 'rspec', '>= 2.0.1' + s.add_development_dependency 'json', '>= 1.4.6' + s.add_development_dependency 'benchmark_suite' + s.add_development_dependency 'ffi' + + if RUBY_PLATFORM =~ /java/ + s.add_development_dependency 'jruby-openssl' + else + s.add_development_dependency 'yajl-ruby', '>= 0.8.1' + end +end diff --git a/.gems/gems/http_parser.rb-0.6.0/lib/http/parser.rb b/.gems/gems/http_parser.rb-0.6.0/lib/http/parser.rb new file mode 100644 index 0000000..4881b03 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/lib/http/parser.rb @@ -0,0 +1 @@ +require 'http_parser' diff --git a/.gems/gems/http_parser.rb-0.6.0/lib/http_parser.rb b/.gems/gems/http_parser.rb-0.6.0/lib/http_parser.rb new file mode 100644 index 0000000..c69f7a0 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/lib/http_parser.rb @@ -0,0 +1,21 @@ +$:.unshift File.expand_path('../', __FILE__) +require 'ruby_http_parser' + +Http = HTTP + +module HTTP + class Parser + class << self + attr_reader :default_header_value_type + + def default_header_value_type=(val) + if (val != :mixed && val != :strings && val != :arrays) + raise ArgumentError, "Invalid header value type" + end + @default_header_value_type = val + end + end + end +end + +HTTP::Parser.default_header_value_type = :mixed diff --git a/.gems/gems/http_parser.rb-0.6.0/spec/parser_spec.rb b/.gems/gems/http_parser.rb-0.6.0/spec/parser_spec.rb new file mode 100644 index 0000000..7134476 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/spec/parser_spec.rb @@ -0,0 +1,350 @@ +require "spec_helper" +require "json" + +describe HTTP::Parser do + before do + @parser = HTTP::Parser.new + + @headers = nil + @body = "" + @started = false + @done = false + + @parser.on_message_begin = proc{ @started = true } + @parser.on_headers_complete = proc { |e| @headers = e } + @parser.on_body = proc { |chunk| @body << chunk } + @parser.on_message_complete = proc{ @done = true } + end + + it "should have initial state" do + @parser.headers.should be_nil + + @parser.http_version.should be_nil + @parser.http_method.should be_nil + @parser.status_code.should be_nil + + @parser.request_url.should be_nil + + @parser.header_value_type.should == :mixed + end + + it "should allow us to set the header value type" do + [:mixed, :arrays, :strings].each do |type| + @parser.header_value_type = type + @parser.header_value_type.should == type + + parser_tmp = HTTP::Parser.new(nil, type) + parser_tmp.header_value_type.should == type + end + end + + it "should allow us to set the default header value type" do + [:mixed, :arrays, :strings].each do |type| + HTTP::Parser.default_header_value_type = type + + parser = HTTP::Parser.new + parser.header_value_type.should == type + end + end + + it "should throw an Argument Error if header value type is invalid" do + proc{ @parser.header_value_type = 'bob' }.should raise_error(ArgumentError) + end + + it "should throw an Argument Error if default header value type is invalid" do + proc{ HTTP::Parser.default_header_value_type = 'bob' }.should raise_error(ArgumentError) + end + + it "should implement basic api" do + @parser << + "GET /test?ok=1 HTTP/1.1\r\n" + + "User-Agent: curl/7.18.0\r\n" + + "Host: 0.0.0.0:5000\r\n" + + "Accept: */*\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "World" + + @started.should be_true + @done.should be_true + + @parser.http_major.should == 1 + @parser.http_minor.should == 1 + @parser.http_version.should == [1,1] + @parser.http_method.should == 'GET' + @parser.status_code.should be_nil + + @parser.request_url.should == '/test?ok=1' + + @parser.headers.should == @headers + @parser.headers['User-Agent'].should == 'curl/7.18.0' + @parser.headers['Host'].should == '0.0.0.0:5000' + + @body.should == "World" + end + + it "should raise errors on invalid data" do + proc{ @parser << "BLAH" }.should raise_error(HTTP::Parser::Error) + end + + it "should abort parser via callback" do + @parser.on_headers_complete = proc { |e| @headers = e; :stop } + + data = + "GET / HTTP/1.0\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "World" + + bytes = @parser << data + + bytes.should == 37 + data[bytes..-1].should == 'World' + + @headers.should == {'Content-Length' => '5'} + @body.should be_empty + @done.should be_false + end + + it "should reset to initial state" do + @parser << "GET / HTTP/1.0\r\n\r\n" + + @parser.http_method.should == 'GET' + @parser.http_version.should == [1,0] + + @parser.request_url.should == '/' + + @parser.reset!.should be_true + + @parser.http_version.should be_nil + @parser.http_method.should be_nil + @parser.status_code.should be_nil + + @parser.request_url.should be_nil + end + + it "should optionally reset parser state on no-body responses" do + @parser.reset!.should be_true + + @head, @complete = 0, 0 + @parser.on_headers_complete = proc {|h| @head += 1; :reset } + @parser.on_message_complete = proc { @complete += 1 } + @parser.on_body = proc {|b| fail } + + head_response = "HTTP/1.1 200 OK\r\nContent-Length:10\r\n\r\n" + + @parser << head_response + @head.should == 1 + @complete.should == 1 + + @parser << head_response + @head.should == 2 + @complete.should == 2 + end + + it "should retain callbacks after reset" do + @parser.reset!.should be_true + + @parser << "GET / HTTP/1.0\r\n\r\n" + @started.should be_true + @headers.should == {} + @done.should be_true + end + + it "should parse headers incrementally" do + request = + "GET / HTTP/1.0\r\n" + + "Header1: value 1\r\n" + + "Header2: value 2\r\n" + + "\r\n" + + while chunk = request.slice!(0,2) and !chunk.empty? + @parser << chunk + end + + @parser.headers.should == { + 'Header1' => 'value 1', + 'Header2' => 'value 2' + } + end + + it "should handle multiple headers using strings" do + @parser.header_value_type = :strings + + @parser << + "GET / HTTP/1.0\r\n" + + "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" + + "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" + + "\r\n" + + @parser.headers["Set-Cookie"].should == "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com, NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly" + end + + it "should handle multiple headers using strings" do + @parser.header_value_type = :arrays + + @parser << + "GET / HTTP/1.0\r\n" + + "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" + + "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" + + "\r\n" + + @parser.headers["Set-Cookie"].should == [ + "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com", + "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly" + ] + end + + it "should handle multiple headers using mixed" do + @parser.header_value_type = :mixed + + @parser << + "GET / HTTP/1.0\r\n" + + "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" + + "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" + + "\r\n" + + @parser.headers["Set-Cookie"].should == [ + "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com", + "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly" + ] + end + + it "should handle a single cookie using mixed" do + @parser.header_value_type = :mixed + + @parser << + "GET / HTTP/1.0\r\n" + + "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" + + "\r\n" + + @parser.headers["Set-Cookie"].should == "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com" + end + + it "should support alternative api" do + callbacks = double('callbacks') + callbacks.stub(:on_message_begin){ @started = true } + callbacks.stub(:on_headers_complete){ |e| @headers = e } + callbacks.stub(:on_body){ |chunk| @body << chunk } + callbacks.stub(:on_message_complete){ @done = true } + + @parser = HTTP::Parser.new(callbacks) + @parser << "GET / HTTP/1.0\r\n\r\n" + + @started.should be_true + @headers.should == {} + @body.should == '' + @done.should be_true + end + + it "should ignore extra content beyond specified length" do + @parser << + "GET / HTTP/1.0\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello" + + " \n" + + @body.should == 'hello' + @done.should be_true + end + + it 'sets upgrade_data if available' do + @parser << + "GET /demo HTTP/1.1\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: WebSocket\r\n\r\n" + + "third key data" + + @parser.upgrade?.should be_true + @parser.upgrade_data.should == 'third key data' + end + + it 'sets upgrade_data to blank if un-available' do + @parser << + "GET /demo HTTP/1.1\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: WebSocket\r\n\r\n" + + @parser.upgrade?.should be_true + @parser.upgrade_data.should == '' + end + + it 'should stop parsing headers when instructed' do + request = "GET /websocket HTTP/1.1\r\n" + + "host: localhost\r\n" + + "connection: Upgrade\r\n" + + "upgrade: websocket\r\n" + + "sec-websocket-key: SD6/hpYbKjQ6Sown7pBbWQ==\r\n" + + "sec-websocket-version: 13\r\n" + + "\r\n" + + @parser.on_headers_complete = proc { |e| :stop } + offset = (@parser << request) + @parser.upgrade?.should be_true + @parser.upgrade_data.should == '' + offset.should == request.length + end + + it "should execute on_body on requests with no content-length" do + @parser.reset!.should be_true + + @head, @complete, @body = 0, 0, 0 + @parser.on_headers_complete = proc {|h| @head += 1 } + @parser.on_message_complete = proc { @complete += 1 } + @parser.on_body = proc {|b| @body += 1 } + + head_response = "HTTP/1.1 200 OK\r\n\r\nstuff" + + @parser << head_response + @parser << '' + @head.should == 1 + @complete.should == 1 + @body.should == 1 + end + + + %w[ request response ].each do |type| + JSON.parse(File.read(File.expand_path("../support/#{type}s.json", __FILE__))).each do |test| + test['headers'] ||= {} + next if !defined?(JRUBY_VERSION) and HTTP::Parser.strict? != test['strict'] + + it "should parse #{type}: #{test['name']}" do + @parser << test['raw'] + + @parser.http_method.should == test['method'] + @parser.keep_alive?.should == test['should_keep_alive'] + + if test.has_key?('upgrade') and test['upgrade'] != 0 + @parser.upgrade?.should be_true + @parser.upgrade_data.should == test['upgrade'] + end + + fields = %w[ + http_major + http_minor + ] + + if test['type'] == 'HTTP_REQUEST' + fields += %w[ + request_url + ] + else + fields += %w[ + status_code + ] + end + + fields.each do |field| + @parser.send(field).should == test[field] + end + + @headers.size.should == test['num_headers'] + @headers.should == test['headers'] + + @body.should == test['body'] + @body.size.should == test['body_size'] if test['body_size'] + end + end + end +end diff --git a/.gems/gems/http_parser.rb-0.6.0/spec/spec_helper.rb b/.gems/gems/http_parser.rb-0.6.0/spec/spec_helper.rb new file mode 100644 index 0000000..a4295f9 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/spec/spec_helper.rb @@ -0,0 +1 @@ +require "http_parser" diff --git a/.gems/gems/http_parser.rb-0.6.0/spec/support/requests.json b/.gems/gems/http_parser.rb-0.6.0/spec/support/requests.json new file mode 100644 index 0000000..dbb6e98 --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/spec/support/requests.json @@ -0,0 +1,612 @@ +[ + { + "name": "curl get", + "type": "HTTP_REQUEST", + "raw": "GET /test HTTP/1.1\r\nUser-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\nHost: 0.0.0.0=5000\r\nAccept: */*\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/test", + "request_url": "/test", + "num_headers": 3, + "headers": { + "User-Agent": "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1", + "Host": "0.0.0.0=5000", + "Accept": "*/*" + }, + "body": "", + "strict": true + }, + { + "name": "firefox get", + "type": "HTTP_REQUEST", + "raw": "GET /favicon.ico HTTP/1.1\r\nHost: 0.0.0.0=5000\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/favicon.ico", + "request_url": "/favicon.ico", + "num_headers": 8, + "headers": { + "Host": "0.0.0.0=5000", + "User-Agent": "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language": "en-us,en;q=0.5", + "Accept-Encoding": "gzip,deflate", + "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", + "Keep-Alive": "300", + "Connection": "keep-alive" + }, + "body": "", + "strict": true + }, + { + "name": "dumbfuck", + "type": "HTTP_REQUEST", + "raw": "GET /dumbfuck HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/dumbfuck", + "request_url": "/dumbfuck", + "num_headers": 1, + "headers": { + "aaaaaaaaaaaaa": "++++++++++" + }, + "body": "", + "strict": true + }, + { + "name": "fragment in url", + "type": "HTTP_REQUEST", + "raw": "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "page=1", + "fragment": "posts-17408", + "request_path": "/forums/1/topics/2375", + "request_url": "/forums/1/topics/2375?page=1#posts-17408", + "num_headers": 0, + "body": "", + "strict": true + }, + { + "name": "get no headers no body", + "type": "HTTP_REQUEST", + "raw": "GET /get_no_headers_no_body/world HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/get_no_headers_no_body/world", + "request_url": "/get_no_headers_no_body/world", + "num_headers": 0, + "body": "", + "strict": true + }, + { + "name": "get one header no body", + "type": "HTTP_REQUEST", + "raw": "GET /get_one_header_no_body HTTP/1.1\r\nAccept: */*\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/get_one_header_no_body", + "request_url": "/get_one_header_no_body", + "num_headers": 1, + "headers": { + "Accept": "*/*" + }, + "body": "", + "strict": true + }, + { + "name": "get funky content length body hello", + "type": "HTTP_REQUEST", + "raw": "GET /get_funky_content_length_body_hello HTTP/1.0\r\nconTENT-Length: 5\r\n\r\nHELLO", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/get_funky_content_length_body_hello", + "request_url": "/get_funky_content_length_body_hello", + "num_headers": 1, + "headers": { + "conTENT-Length": "5" + }, + "body": "HELLO", + "strict": true + }, + { + "name": "post identity body world", + "type": "HTTP_REQUEST", + "raw": "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\nAccept: */*\r\nTransfer-Encoding: identity\r\nContent-Length: 5\r\n\r\nWorld", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "POST", + "query_string": "q=search", + "fragment": "hey", + "request_path": "/post_identity_body_world", + "request_url": "/post_identity_body_world?q=search#hey", + "num_headers": 3, + "headers": { + "Accept": "*/*", + "Transfer-Encoding": "identity", + "Content-Length": "5" + }, + "body": "World", + "strict": true + }, + { + "name": "post - chunked body: all your base are belong to us", + "type": "HTTP_REQUEST", + "raw": "POST /post_chunked_all_your_base HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1e\r\nall your base are belong to us\r\n0\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "POST", + "query_string": "", + "fragment": "", + "request_path": "/post_chunked_all_your_base", + "request_url": "/post_chunked_all_your_base", + "num_headers": 1, + "headers": { + "Transfer-Encoding": "chunked" + }, + "body": "all your base are belong to us", + "strict": true + }, + { + "name": "two chunks ; triple zero ending", + "type": "HTTP_REQUEST", + "raw": "POST /two_chunks_mult_zero_end HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n000\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "POST", + "query_string": "", + "fragment": "", + "request_path": "/two_chunks_mult_zero_end", + "request_url": "/two_chunks_mult_zero_end", + "num_headers": 1, + "headers": { + "Transfer-Encoding": "chunked" + }, + "body": "hello world", + "strict": true + }, + { + "name": "chunked with trailing headers. blech.", + "type": "HTTP_REQUEST", + "raw": "POST /chunked_w_trailing_headers HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n0\r\nVary: *\r\nContent-Type: text/plain\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "POST", + "query_string": "", + "fragment": "", + "request_path": "/chunked_w_trailing_headers", + "request_url": "/chunked_w_trailing_headers", + "num_headers": 3, + "headers": { + "Transfer-Encoding": "chunked", + "Vary": "*", + "Content-Type": "text/plain" + }, + "body": "hello world", + "strict": true + }, + { + "name": "with bullshit after the length", + "type": "HTTP_REQUEST", + "raw": "POST /chunked_w_bullshit_after_length HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n6; blahblah; blah\r\n world\r\n0\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "POST", + "query_string": "", + "fragment": "", + "request_path": "/chunked_w_bullshit_after_length", + "request_url": "/chunked_w_bullshit_after_length", + "num_headers": 1, + "headers": { + "Transfer-Encoding": "chunked" + }, + "body": "hello world", + "strict": true + }, + { + "name": "with quotes", + "type": "HTTP_REQUEST", + "raw": "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "foo=\"bar\"", + "fragment": "", + "request_path": "/with_\"stupid\"_quotes", + "request_url": "/with_\"stupid\"_quotes?foo=\"bar\"", + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "apachebench get", + "type": "HTTP_REQUEST", + "raw": "GET /test HTTP/1.0\r\nHost: 0.0.0.0:5000\r\nUser-Agent: ApacheBench/2.3\r\nAccept: */*\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/test", + "request_url": "/test", + "num_headers": 3, + "headers": { + "Host": "0.0.0.0:5000", + "User-Agent": "ApacheBench/2.3", + "Accept": "*/*" + }, + "body": "", + "strict": true + }, + { + "name": "query url with question mark", + "type": "HTTP_REQUEST", + "raw": "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "foo=bar?baz", + "fragment": "", + "request_path": "/test.cgi", + "request_url": "/test.cgi?foo=bar?baz", + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "newline prefix get", + "type": "HTTP_REQUEST", + "raw": "\r\nGET /test HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/test", + "request_url": "/test", + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "upgrade request", + "type": "HTTP_REQUEST", + "raw": "GET /demo HTTP/1.1\r\nHost: example.com\r\nConnection: Upgrade\r\nSec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\nSec-WebSocket-Protocol: sample\r\nUpgrade: WebSocket\r\nSec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\nOrigin: http://example.com\r\n\r\nHot diggity dogg", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/demo", + "request_url": "/demo", + "num_headers": 7, + "upgrade": "Hot diggity dogg", + "headers": { + "Host": "example.com", + "Connection": "Upgrade", + "Sec-WebSocket-Key2": "12998 5 Y3 1 .P00", + "Sec-WebSocket-Protocol": "sample", + "Upgrade": "WebSocket", + "Sec-WebSocket-Key1": "4 @1 46546xW%0l 1 5", + "Origin": "http://example.com" + }, + "body": "", + "strict": true + }, + { + "name": "connect request", + "type": "HTTP_REQUEST", + "raw": "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\nUser-agent: Mozilla/1.1N\r\nProxy-authorization: basic aGVsbG86d29ybGQ=\r\n\r\nsome data\r\nand yet even more data", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "method": "CONNECT", + "query_string": "", + "fragment": "", + "request_path": "", + "request_url": "0-home0.netscape.com:443", + "num_headers": 2, + "upgrade": "some data\r\nand yet even more data", + "headers": { + "User-agent": "Mozilla/1.1N", + "Proxy-authorization": "basic aGVsbG86d29ybGQ=" + }, + "body": "", + "strict": true + }, + { + "name": "report request", + "type": "HTTP_REQUEST", + "raw": "REPORT /test HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "REPORT", + "query_string": "", + "fragment": "", + "request_path": "/test", + "request_url": "/test", + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "request with no http version", + "type": "HTTP_REQUEST", + "raw": "GET /\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 0, + "http_minor": 9, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/", + "request_url": "/", + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "m-search request", + "type": "HTTP_REQUEST", + "raw": "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nST: \"ssdp:all\"\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "M-SEARCH", + "query_string": "", + "fragment": "", + "request_path": "*", + "request_url": "*", + "num_headers": 3, + "headers": { + "HOST": "239.255.255.250:1900", + "MAN": "\"ssdp:discover\"", + "ST": "\"ssdp:all\"" + }, + "body": "", + "strict": true + }, + { + "name": "line folding in header value", + "type": "HTTP_REQUEST", + "raw": "GET / HTTP/1.1\r\nLine1: abc\r\n\tdef\r\n ghi\r\n\t\tjkl\r\n mno \r\n\t \tqrs\r\nLine2: \t line2\t\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "/", + "request_url": "/", + "num_headers": 2, + "headers": { + "Line1": "abcdefghijklmno qrs", + "Line2": "line2\t" + }, + "body": "", + "strict": true + }, + { + "name": "host terminated by a query string", + "type": "HTTP_REQUEST", + "raw": "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "hail=all", + "fragment": "", + "request_path": "", + "request_url": "http://hypnotoad.org?hail=all", + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "host:port terminated by a query string", + "type": "HTTP_REQUEST", + "raw": "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "hail=all", + "fragment": "", + "request_path": "", + "request_url": "http://hypnotoad.org:1234?hail=all", + "port": 1234, + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "host:port terminated by a space", + "type": "HTTP_REQUEST", + "raw": "GET http://hypnotoad.org:1234 HTTP/1.1\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "", + "fragment": "", + "request_path": "", + "request_url": "http://hypnotoad.org:1234", + "port": 1234, + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "PATCH request", + "type": "HTTP_REQUEST", + "raw": "PATCH /file.txt HTTP/1.1\r\nHost: www.example.com\r\nContent-Type: application/example\r\nIf-Match: \"e0023aa4e\"\r\nContent-Length: 10\r\n\r\ncccccccccc", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "PATCH", + "query_string": "", + "fragment": "", + "request_path": "/file.txt", + "request_url": "/file.txt", + "num_headers": 4, + "headers": { + "Host": "www.example.com", + "Content-Type": "application/example", + "If-Match": "\"e0023aa4e\"", + "Content-Length": "10" + }, + "body": "cccccccccc", + "strict": true + }, + { + "name": "connect caps request", + "type": "HTTP_REQUEST", + "raw": "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\nUser-agent: Mozilla/1.1N\r\nProxy-authorization: basic aGVsbG86d29ybGQ=\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "method": "CONNECT", + "query_string": "", + "fragment": "", + "request_path": "", + "request_url": "HOME0.NETSCAPE.COM:443", + "num_headers": 2, + "upgrade": "", + "headers": { + "User-agent": "Mozilla/1.1N", + "Proxy-authorization": "basic aGVsbG86d29ybGQ=" + }, + "body": "", + "strict": true + }, + { + "name": "utf-8 path request", + "type": "HTTP_REQUEST", + "strict": false, + "raw": "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\nHost: github.com\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "method": "GET", + "query_string": "q=1", + "fragment": "narf", + "request_path": "/δ¶/δt/pope", + "request_url": "/δ¶/δt/pope?q=1#narf", + "num_headers": 1, + "headers": { + "Host": "github.com" + }, + "body": "" + }, + { + "name": "hostname underscore", + "type": "HTTP_REQUEST", + "strict": false, + "raw": "CONNECT home_0.netscape.com:443 HTTP/1.0\r\nUser-agent: Mozilla/1.1N\r\nProxy-authorization: basic aGVsbG86d29ybGQ=\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "method": "CONNECT", + "query_string": "", + "fragment": "", + "request_path": "", + "request_url": "home_0.netscape.com:443", + "num_headers": 2, + "upgrade": "", + "headers": { + "User-agent": "Mozilla/1.1N", + "Proxy-authorization": "basic aGVsbG86d29ybGQ=" + }, + "body": "" + } +] \ No newline at end of file diff --git a/.gems/gems/http_parser.rb-0.6.0/spec/support/responses.json b/.gems/gems/http_parser.rb-0.6.0/spec/support/responses.json new file mode 100644 index 0000000..6dde20b --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/spec/support/responses.json @@ -0,0 +1,375 @@ +[ + { + "name": "google 301", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 301 Moved Permanently\r\nLocation: http://www.google.com/\r\nContent-Type: text/html; charset=UTF-8\r\nDate: Sun, 26 Apr 2009 11:11:49 GMT\r\nExpires: Tue, 26 May 2009 11:11:49 GMT\r\nX-$PrototypeBI-Version: 1.6.0.3\r\nCache-Control: public, max-age=2592000\r\nServer: gws\r\nContent-Length: 219 \r\n\r\n\n301 Moved\n

    301 Moved

    \nThe document has moved\nhere.\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 301, + "num_headers": 8, + "headers": { + "Location": "http://www.google.com/", + "Content-Type": "text/html; charset=UTF-8", + "Date": "Sun, 26 Apr 2009 11:11:49 GMT", + "Expires": "Tue, 26 May 2009 11:11:49 GMT", + "X-$PrototypeBI-Version": "1.6.0.3", + "Cache-Control": "public, max-age=2592000", + "Server": "gws", + "Content-Length": "219 " + }, + "body": "\n301 Moved\n

    301 Moved

    \nThe document has moved\nhere.\r\n\r\n", + "strict": true + }, + { + "name": "no content-length response", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nDate: Tue, 04 Aug 2009 07:59:32 GMT\r\nServer: Apache\r\nX-Powered-By: Servlet/2.5 JSP/2.1\r\nContent-Type: text/xml; charset=utf-8\r\nConnection: close\r\n\r\n\n\n \n \n SOAP-ENV:Client\n Client Error\n \n \n", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 5, + "headers": { + "Date": "Tue, 04 Aug 2009 07:59:32 GMT", + "Server": "Apache", + "X-Powered-By": "Servlet/2.5 JSP/2.1", + "Content-Type": "text/xml; charset=utf-8", + "Connection": "close" + }, + "body": "\n\n \n \n SOAP-ENV:Client\n Client Error\n \n \n", + "strict": true + }, + { + "name": "404 no headers no body", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 404 Not Found\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 1, + "status_code": 404, + "num_headers": 0, + "headers": { + + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "301 no response phrase", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 301\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 1, + "status_code": 301, + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "200 trailing space on chunked body", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n25 \r\nThis is the data in the first chunk\r\n\r\n1C\r\nand this is the second one\r\n\r\n0 \r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 2, + "headers": { + "Content-Type": "text/plain", + "Transfer-Encoding": "chunked" + }, + "body_size": 65, + "body": "This is the data in the first chunk\r\nand this is the second one\r\n", + "strict": true + }, + { + "name": "no carriage ret", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\nConnection: close\n\nthese headers are from http://news.ycombinator.com/", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 2, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Connection": "close" + }, + "body": "these headers are from http://news.ycombinator.com/", + "strict": true + }, + { + "name": "proxy connection", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 11\r\nProxy-Connection: close\r\nDate: Thu, 31 Dec 2009 20:55:48 +0000\r\n\r\nhello world", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 4, + "headers": { + "Content-Type": "text/html; charset=UTF-8", + "Content-Length": "11", + "Proxy-Connection": "close", + "Date": "Thu, 31 Dec 2009 20:55:48 +0000" + }, + "body": "hello world", + "strict": true + }, + { + "name": "underscore header key", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nServer: DCLK-AdSvr\r\nContent-Type: text/xml\r\nContent-Length: 0\r\nDCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 4, + "headers": { + "Server": "DCLK-AdSvr", + "Content-Type": "text/xml", + "Content-Length": "0", + "DCLK_imp": "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" + }, + "body": "", + "strict": true + }, + { + "name": "bonjourmadame.fr", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.0 301 Moved Permanently\r\nDate: Thu, 03 Jun 2010 09:56:32 GMT\r\nServer: Apache/2.2.3 (Red Hat)\r\nCache-Control: public\r\nPragma: \r\nLocation: http://www.bonjourmadame.fr/\r\nVary: Accept-Encoding\r\nContent-Length: 0\r\nContent-Type: text/html; charset=UTF-8\r\nConnection: keep-alive\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "status_code": 301, + "num_headers": 9, + "headers": { + "Date": "Thu, 03 Jun 2010 09:56:32 GMT", + "Server": "Apache/2.2.3 (Red Hat)", + "Cache-Control": "public", + "Pragma": "", + "Location": "http://www.bonjourmadame.fr/", + "Vary": "Accept-Encoding", + "Content-Length": "0", + "Content-Type": "text/html; charset=UTF-8", + "Connection": "keep-alive" + }, + "body": "", + "strict": true + }, + { + "name": "field underscore", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nDate: Tue, 28 Sep 2010 01:14:13 GMT\r\nServer: Apache\r\nCache-Control: no-cache, must-revalidate\r\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\r\n.et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\nVary: Accept-Encoding\r\n_eep-Alive: timeout=45\r\n_onnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n0\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 11, + "headers": { + "Date": "Tue, 28 Sep 2010 01:14:13 GMT", + "Server": "Apache", + "Cache-Control": "no-cache, must-revalidate", + "Expires": "Mon, 26 Jul 1997 05:00:00 GMT", + ".et-Cookie": "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com", + "Vary": "Accept-Encoding", + "_eep-Alive": "timeout=45", + "_onnection": "Keep-Alive", + "Transfer-Encoding": "chunked", + "Content-Type": "text/html", + "Connection": "close" + }, + "body": "", + "strict": true + }, + { + "name": "non-ASCII in status line", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 500 Oriëntatieprobleem\r\nDate: Fri, 5 Nov 2010 23:07:12 GMT+2\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 500, + "num_headers": 3, + "headers": { + "Date": "Fri, 5 Nov 2010 23:07:12 GMT+2", + "Content-Length": "0", + "Connection": "close" + }, + "body": "", + "strict": true + }, + { + "name": "http version 0.9", + "type": "HTTP_RESPONSE", + "raw": "HTTP/0.9 200 OK\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 0, + "http_minor": 9, + "status_code": 200, + "num_headers": 0, + "headers": { + + }, + "body": "", + "strict": true + }, + { + "name": "neither content-length nor transfer-encoding response", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello world", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 1, + "headers": { + "Content-Type": "text/plain" + }, + "body": "hello world", + "strict": true + }, + { + "name": "HTTP/1.0 with keep-alive and EOF-terminated 200 status", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.0 200 OK\r\nConnection: keep-alive\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 0, + "status_code": 200, + "num_headers": 1, + "headers": { + "Connection": "keep-alive" + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "HTTP/1.0 with keep-alive and a 204 status", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.0 204 No content\r\nConnection: keep-alive\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 0, + "status_code": 204, + "num_headers": 1, + "headers": { + "Connection": "keep-alive" + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "HTTP/1.1 with an EOF-terminated 200 status", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": true, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 0, + "headers": { + + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "HTTP/1.1 with a 204 status", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 204 No content\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 204, + "num_headers": 0, + "headers": { + + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "HTTP/1.1 with a 204 status and keep-alive disabled", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 204 No content\r\nConnection: close\r\n\r\n", + "should_keep_alive": false, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 204, + "num_headers": 1, + "headers": { + "Connection": "close" + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "HTTP/1.1 with chunked endocing and a 200 response", + "type": "HTTP_RESPONSE", + "raw": "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 1, + "headers": { + "Transfer-Encoding": "chunked" + }, + "body_size": 0, + "body": "", + "strict": true + }, + { + "name": "field space", + "type": "HTTP_RESPONSE", + "strict": false, + "raw": "HTTP/1.1 200 OK\r\nServer: Microsoft-IIS/6.0\r\nX-Powered-By: ASP.NET\r\nen-US Content-Type: text/xml\r\nContent-Type: text/xml\r\nContent-Length: 16\r\nDate: Fri, 23 Jul 2010 18:45:38 GMT\r\nConnection: keep-alive\r\n\r\nhello", + "should_keep_alive": true, + "message_complete_on_eof": false, + "http_major": 1, + "http_minor": 1, + "status_code": 200, + "num_headers": 7, + "headers": { + "Server": "Microsoft-IIS/6.0", + "X-Powered-By": "ASP.NET", + "en-US Content-Type": "text/xml", + "Content-Type": "text/xml", + "Content-Length": "16", + "Date": "Fri, 23 Jul 2010 18:45:38 GMT", + "Connection": "keep-alive" + }, + "body": "hello" + } +] \ No newline at end of file diff --git a/.gems/gems/http_parser.rb-0.6.0/tasks/compile.rake b/.gems/gems/http_parser.rb-0.6.0/tasks/compile.rake new file mode 100644 index 0000000..22d6f6d --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/tasks/compile.rake @@ -0,0 +1,42 @@ +require 'rubygems/package_task' +require 'rake/extensiontask' +require 'rake/javaextensiontask' + +def gemspec + @clean_gemspec ||= eval(File.read(File.expand_path('../../http_parser.rb.gemspec', __FILE__))) +end + +Gem::PackageTask.new(gemspec) do |pkg| +end + +if RUBY_PLATFORM =~ /java/ + Rake::JavaExtensionTask.new("ruby_http_parser", gemspec) do |ext| + ext.classpath = File.expand_path('../../ext/ruby_http_parser/vendor/http-parser-java/ext/primitives.jar', __FILE__) + end +else + Rake::ExtensionTask.new("ruby_http_parser", gemspec) do |ext| + unless RUBY_PLATFORM =~ /mswin|mingw/ + ext.cross_compile = true + ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60'] + + # inject 1.8/1.9 pure-ruby entry point + ext.cross_compiling do |spec| + spec.files += ['lib/ruby_http_parser.rb'] + end + end + end +end + +file 'lib/ruby_http_parser.rb' do |t| + File.open(t.name, 'wb') do |f| + f.write <<-eoruby +RUBY_VERSION =~ /(\\d+.\\d+)/ +require "\#{$1}/ruby_http_parser" + eoruby + end + at_exit{ FileUtils.rm t.name if File.exists?(t.name) } +end + +if Rake::Task.task_defined?(:cross) + task :cross => 'lib/ruby_http_parser.rb' +end diff --git a/.gems/gems/http_parser.rb-0.6.0/tasks/fixtures.rake b/.gems/gems/http_parser.rb-0.6.0/tasks/fixtures.rake new file mode 100644 index 0000000..b5d36ef --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/tasks/fixtures.rake @@ -0,0 +1,71 @@ +desc "Generate test fixtures" +task :fixtures => :submodules do + require 'yajl' + data = File.read File.expand_path('../../ext/ruby_http_parser/vendor/http-parser/test.c', __FILE__) + + %w[ requests responses ].each do |type| + # find test definitions in between requests/responses[]= and .name=NULL + tmp = data[/#{type}\[\]\s*=(.+?),\s*\{\s*\.name=\s*NULL/m, 1] + + # replace first { with a [ (parsing an array of test cases) + tmp.sub!('{','[') + + # replace booleans + tmp.gsub!('TRUE', 'true') + tmp.gsub!('FALSE', 'false') + + # mark strict mode tests + tmp.gsub!(%r|#if\s+!HTTP_PARSER_STRICT(.+?)#endif\s*/\*\s*!HTTP_PARSER_STRICT.+\n|m){ + $1.gsub(/^(.+,\.type= .+)$/, "\\1\n, .strict= false") + } + + # remove macros and comments + tmp.gsub!(/^#(if|elif|endif|define).+$/,'') + tmp.gsub!(/\/\*(.+?)\*\/$/,'') + + # HTTP_* enums become strings + tmp.gsub!(/(= )(HTTP_\w+)/){ + "#{$1}#{$2.sub('MSEARCH','M-SEARCH').dump}" + } + + # join multiline strings for body and raw data + tmp.gsub!(/((body|raw)\s*=)(.+?)(\n\s+[\},])/m){ + before, after = $1, $4 + raw = $3.split("\n").map{ |l| l.strip[1..-2] }.join('') + "#{before} \"#{raw}\" #{after}" + } + + # make headers an array of array tuples + tmp.gsub!(/(\.headers\s*=)(.+?)(\s*,\.)/m){ + before, after = $1, $3 + raw = $2.gsub('{', '[').gsub('}', ']') + "#{before} #{raw} #{after}" + } + + # .name= becomes "name": + tmp.gsub!(/^(.{2,5})\.(\w+)\s*=/){ + "#{$1}#{$2.dump}: " + } + + # evaluate addition expressions + tmp.gsub!(/(body_size\":\s*)(\d+)\+(\d+)/){ + "#{$1}#{$2.to_i+$3.to_i}" + } + + # end result array + tmp << ']' + + # normalize data + results = Yajl.load(tmp, :symbolize_keys => true) + results.map{ |res| + res[:headers] and res[:headers] = Hash[*res[:headers].flatten] + res[:method] and res[:method].gsub!(/^HTTP_/, '') + res[:strict] = true unless res.has_key?(:strict) + } + + # write to a file + File.open("spec/support/#{type}.json", 'w'){ |f| + f.write Yajl.dump(results, :pretty => true) + } + end +end diff --git a/.gems/gems/http_parser.rb-0.6.0/tasks/spec.rake b/.gems/gems/http_parser.rb-0.6.0/tasks/spec.rake new file mode 100644 index 0000000..8f5d9ea --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/tasks/spec.rake @@ -0,0 +1,5 @@ +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new do |t| + t.rspec_opts = %w(-fs -c) +end diff --git a/.gems/gems/http_parser.rb-0.6.0/tasks/submodules.rake b/.gems/gems/http_parser.rb-0.6.0/tasks/submodules.rake new file mode 100644 index 0000000..d978e9f --- /dev/null +++ b/.gems/gems/http_parser.rb-0.6.0/tasks/submodules.rake @@ -0,0 +1,7 @@ +desc "Fetch upstream submodules" +task :submodules do + if Dir['ext/ruby_http_parser/vendor/http-parser/*'].empty? + sh 'git submodule init' + sh 'git submodule update' + end +end diff --git a/.gems/gems/memoizable-0.4.2/CONTRIBUTING.md b/.gems/gems/memoizable-0.4.2/CONTRIBUTING.md new file mode 100644 index 0000000..333b403 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/CONTRIBUTING.md @@ -0,0 +1,11 @@ +Contributing +------------ + +* If you want your code merged into the mainline, please discuss the proposed changes with me before doing any work on it. This library is still in early development, and the direction it is going may not always be clear. Some features may not be appropriate yet, may need to be deferred until later when the foundation for them is laid, or may be more applicable in a plugin. +* Fork the project. +* Make your feature addition or bug fix. + * Follow this [style guide](https://github.com/dkubb/styleguide). +* Add specs for it. This is important so I don't break it in a future version unintentionally. Tests must cover all branches within the code, and code must be fully covered. +* Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) +* Run "rake ci". This must pass and not show any regressions in the metrics for the code to be merged. +* Send me a pull request. Bonus points for topic branches. diff --git a/.gems/gems/memoizable-0.4.2/LICENSE.md b/.gems/gems/memoizable-0.4.2/LICENSE.md new file mode 100644 index 0000000..46a93e6 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2013 Dan Kubb, Erik Michaels-Ober + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/memoizable-0.4.2/README.md b/.gems/gems/memoizable-0.4.2/README.md new file mode 100644 index 0000000..2ff6ff9 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/README.md @@ -0,0 +1,111 @@ +# Memoizable + +[![Gem Version](http://img.shields.io/gem/v/memoizable.svg)][gem] +[![Build Status](http://img.shields.io/travis/dkubb/memoizable.svg)][travis] +[![Dependency Status](http://img.shields.io/gemnasium/dkubb/memoizable.svg)][gemnasium] +[![Code Climate](http://img.shields.io/codeclimate/github/dkubb/memoizable.svg)][codeclimate] +[![Coverage Status](http://img.shields.io/coveralls/dkubb/memoizable.svg)][coveralls] + +[gem]: https://rubygems.org/gems/memoizable +[travis]: https://travis-ci.org/dkubb/memoizable +[gemnasium]: https://gemnasium.com/dkubb/memoizable +[codeclimate]: https://codeclimate.com/github/dkubb/memoizable +[coveralls]: https://coveralls.io/r/dkubb/memoizable + +Memoize method return values + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for details. + +## Rationale + +Memoization is an optimization that saves the return value of a method so it +doesn't need to be re-computed every time that method is called. For example, +perhaps you've written a method like this: + +```ruby +class Planet + # This is the equation for the area of a sphere. If it's true for a + # particular instance of a planet, then that planet is spherical. + def spherical? + 4 * Math::PI * radius ** 2 == area + end +end +``` + +This code will re-compute whether a particular planet is spherical every time +the method is called. If the method is called more than once, it may be more +efficient to save the computed value in an instance variable, like so: + +```ruby +class Planet + def spherical? + @spherical ||= 4 * Math::PI * radius ** 2 == area + end +end +``` + +One problem with this approach is that, if the return value is `false`, the +value will still be computed each time the method is called. It also becomes +unweildy for methods that grow to be longer than one line. + +These problems can be solved by mixing-in the `Memoizable` module and memoizing +the method. + +```ruby +require 'memoizable' + +class Planet + include Memoizable + def spherical? + 4 * Math::PI * radius ** 2 == area + end + memoize :spherical? +end +``` + +## Warning + +The example above assumes that the radius and area of a planet will not change +over time. This seems like a reasonable assumption but such an assumption is +not safe in every domain. If it was possible for one of the attributes to +change between method calls, memoizing that value could produce the wrong +result. Please keep this in mind when considering which methods to memoize. + +Supported Ruby Versions +----------------------- + +This library aims to support and is [tested against][travis] the following Ruby +implementations: + +* Ruby 1.8.7 +* Ruby 1.9.2 +* Ruby 1.9.3 +* Ruby 2.0.0 +* Ruby 2.1.0 +* [JRuby][] +* [Rubinius][] +* [Ruby Enterprise Edition][ree] + +[jruby]: http://jruby.org/ +[rubinius]: http://rubini.us/ +[ree]: http://www.rubyenterpriseedition.com/ + +If something doesn't work on one of these versions, it's a bug. + +This library may inadvertently work (or seem to work) on other Ruby versions or +implementations, however support will only be provided for the implementations +listed above. + +If you would like this library to support another Ruby version or +implementation, you may volunteer to be a maintainer. Being a maintainer +entails making sure all tests run and pass on that implementation. When +something breaks on your implementation, you will be responsible for providing +patches in a timely fashion. If critical issues for a particular implementation +exist at the time of a major release, support for that Ruby version may be +dropped. + +## Copyright + +Copyright © 2013 Dan Kubb, Erik Michaels-Ober. See LICENSE for details. diff --git a/.gems/gems/memoizable-0.4.2/Rakefile b/.gems/gems/memoizable-0.4.2/Rakefile new file mode 100644 index 0000000..242da90 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/Rakefile @@ -0,0 +1,10 @@ +# encoding: utf-8 + +require 'bundler' +require 'rspec/core/rake_task' + +Bundler::GemHelper.install_tasks +RSpec::Core::RakeTask.new(:spec) + +task :test => :spec +task :default => :spec diff --git a/.gems/gems/memoizable-0.4.2/lib/memoizable.rb b/.gems/gems/memoizable-0.4.2/lib/memoizable.rb new file mode 100644 index 0000000..375e179 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/lib/memoizable.rb @@ -0,0 +1,33 @@ +# encoding: utf-8 + +require 'monitor' +require 'thread_safe' + +require 'memoizable/instance_methods' +require 'memoizable/method_builder' +require 'memoizable/module_methods' +require 'memoizable/memory' +require 'memoizable/version' + +# Allow methods to be memoized +module Memoizable + include InstanceMethods + + # Default freezer + Freezer = lambda { |object| object.freeze }.freeze + + # Hook called when module is included + # + # @param [Module] descendant + # the module or class including Memoizable + # + # @return [self] + # + # @api private + def self.included(descendant) + super + descendant.extend(ModuleMethods) + end + private_class_method :included + +end # Memoizable diff --git a/.gems/gems/memoizable-0.4.2/lib/memoizable/instance_methods.rb b/.gems/gems/memoizable-0.4.2/lib/memoizable/instance_methods.rb new file mode 100644 index 0000000..271387d --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/lib/memoizable/instance_methods.rb @@ -0,0 +1,49 @@ +# encoding: utf-8 + +module Memoizable + + # Methods mixed in to memoizable instances + module InstanceMethods + + # Freeze the object + # + # @example + # object.freeze # object is now frozen + # + # @return [Object] + # + # @api public + def freeze + memoized_method_cache # initialize method cache + super + end + + # Sets a memoized value for a method + # + # @example + # object.memoize(hash: 12345) + # + # @param [Hash{Symbol => Object}] data + # the data to memoize + # + # @return [self] + # + # @api public + def memoize(data) + data.each { |name, value| memoized_method_cache[name] = value } + self + end + + private + + # The memoized method results + # + # @return [Hash] + # + # @api private + def memoized_method_cache + @_memoized_method_cache ||= Memory.new + end + + end # InstanceMethods +end # Memoizable diff --git a/.gems/gems/memoizable-0.4.2/lib/memoizable/memory.rb b/.gems/gems/memoizable-0.4.2/lib/memoizable/memory.rb new file mode 100644 index 0000000..4aa0d7a --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/lib/memoizable/memory.rb @@ -0,0 +1,104 @@ +# encoding: utf-8 + +module Memoizable + + # Storage for memoized methods + class Memory + + # Initialize the memory storage for memoized methods + # + # @param [ThreadSafe::Cache] memory + # + # @return [undefined] + # + # @api private + def initialize + @memory = ThreadSafe::Cache.new + @monitor = Monitor.new + freeze + end + + # Get the value from memory + # + # @param [Symbol] name + # + # @return [Object] + # + # @api public + def [](name) + @memory.fetch(name) do + fail NameError, "No method #{name} is memoized" + end + end + + # Store the value in memory + # + # @param [Symbol] name + # @param [Object] value + # + # @return [undefined] + # + # @api public + def []=(name, value) + memoized = true + @memory.compute_if_absent(name) do + memoized = false + value + end + fail ArgumentError, "The method #{name} is already memoized" if memoized + end + + # Fetch the value from memory, or store it if it does not exist + # + # @param [Symbol] name + # + # @yieldreturn [Object] + # the value to memoize + # + # @api public + def fetch(name) + @memory.fetch(name) do # check for the key + @monitor.synchronize do # acquire a lock if the key is not found + @memory.fetch(name) do # recheck under lock + self[name] = yield # set the value + end + end + end + end + + # Test if the name has a value in memory + # + # @param [Symbol] name + # + # @return [Boolean] + # + # @api public + def key?(name) + @memory.key?(name) + end + + # A hook that allows Marshal to dump the object + # + # @return [Hash] + # A hash used to populate the internal memory + # + # @api public + def marshal_dump + @memory.marshal_dump + end + + # A hook that allows Marshal to load the object + # + # @param [Hash] hash + # A hash used to populate the internal memory + # + # @return [undefined] + # + # @api public + def marshal_load(hash) + initialize + @memory.marshal_load(hash) + end + + end # Memory +end # Memoizable diff --git a/.gems/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb b/.gems/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb new file mode 100644 index 0000000..d41483f --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb @@ -0,0 +1,145 @@ +# encoding: utf-8 + +module Memoizable + + # Build the memoized method + class MethodBuilder + + # Raised when the method arity is invalid + class InvalidArityError < ArgumentError + + # Initialize an invalid arity exception + # + # @param [Module] descendant + # @param [Symbol] method + # @param [Integer] arity + # + # @api private + def initialize(descendant, method, arity) + super("Cannot memoize #{descendant}##{method}, its arity is #{arity}") + end + + end # InvalidArityError + + # Raised when a block is passed to a memoized method + class BlockNotAllowedError < ArgumentError + + # Initialize a block not allowed exception + # + # @param [Module] descendant + # @param [Symbol] method + # + # @api private + def initialize(descendant, method) + super("Cannot pass a block to #{descendant}##{method}, it is memoized") + end + + end # BlockNotAllowedError + + # The original method before memoization + # + # @return [UnboundMethod] + # + # @api public + attr_reader :original_method + + # Initialize an object to build a memoized method + # + # @param [Module] descendant + # @param [Symbol] method_name + # @param [#call] freezer + # + # @return [undefined] + # + # @api private + def initialize(descendant, method_name, freezer) + @descendant = descendant + @method_name = method_name + @freezer = freezer + @original_visibility = visibility + @original_method = @descendant.instance_method(@method_name) + assert_arity(@original_method.arity) + end + + # Build a new memoized method + # + # @example + # method_builder.call # => creates new method + # + # @return [MethodBuilder] + # + # @api public + def call + remove_original_method + create_memoized_method + set_method_visibility + self + end + + private + + # Assert the method arity is zero + # + # @param [Integer] arity + # + # @return [undefined] + # + # @raise [InvalidArityError] + # + # @api private + def assert_arity(arity) + if arity.nonzero? + fail InvalidArityError.new(@descendant, @method_name, arity) + end + end + + # Remove the original method + # + # @return [undefined] + # + # @api private + def remove_original_method + name = @method_name + @descendant.module_eval { undef_method(name) } + end + + # Create a new memoized method + # + # @return [undefined] + # + # @api private + def create_memoized_method + name, method, freezer = @method_name, @original_method, @freezer + @descendant.module_eval do + define_method(name) do |&block| + fail BlockNotAllowedError.new(self.class, name) if block + memoized_method_cache.fetch(name) do + freezer.call(method.bind(self).call) + end + end + end + end + + # Set the memoized method visibility to match the original method + # + # @return [undefined] + # + # @api private + def set_method_visibility + @descendant.send(@original_visibility, @method_name) + end + + # Get the visibility of the original method + # + # @return [Symbol] + # + # @api private + def visibility + if @descendant.private_method_defined?(@method_name) then :private + elsif @descendant.protected_method_defined?(@method_name) then :protected + else :public + end + end + + end # MethodBuilder +end # Memoizable diff --git a/.gems/gems/memoizable-0.4.2/lib/memoizable/module_methods.rb b/.gems/gems/memoizable-0.4.2/lib/memoizable/module_methods.rb new file mode 100644 index 0000000..1ffdf34 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/lib/memoizable/module_methods.rb @@ -0,0 +1,125 @@ +# encoding: utf-8 + +module Memoizable + + # Methods mixed in to memoizable singleton classes + module ModuleMethods + + # Return default deep freezer + # + # @return [#call] + # + # @api private + def freezer + Freezer + end + + # Memoize a list of methods + # + # @example + # memoize :hash + # + # @param [Array] methods + # a list of methods to memoize + # + # @return [self] + # + # @api public + def memoize(*methods) + methods.each(&method(:memoize_method)) + self + end + + # Test if an instance method is memoized + # + # @example + # class Foo + # include Memoizable + # + # def bar + # end + # memoize :bar + # end + # + # Foo.memoized?(:bar) # true + # Foo.memoized?(:baz) # false + # + # @param [Symbol] name + # + # @return [Boolean] + # true if method is memoized, false if not + # + # @api private + def memoized?(name) + memoized_methods.key?(name) + end + + # Return unmemoized instance method + # + # @example + # + # class Foo + # include Memoizable + # + # def bar + # end + # memoize :bar + # end + # + # Foo.unmemoized_instance_method(:bar) + # + # @param [Symbol] name + # + # @return [UnboundMethod] + # the memoized method + # + # @raise [NameError] + # raised if the method is unknown + # + # @api public + def unmemoized_instance_method(name) + memoized_methods[name].original_method + end + + private + + # Hook called when module is included + # + # @param [Module] descendant + # the module including ModuleMethods + # + # @return [self] + # + # @api private + def included(descendant) + super + descendant.module_eval { include Memoizable } + end + + # Memoize the named method + # + # @param [Symbol] method_name + # a method name to memoize + # + # @return [undefined] + # + # @api private + def memoize_method(method_name) + memoized_methods[method_name] = MethodBuilder.new( + self, + method_name, + freezer + ).call + end + + # Return method builder registry + # + # @return [Hash] + # + # @api private + def memoized_methods + @_memoized_methods ||= Memory.new + end + + end # ModuleMethods +end # Memoizable diff --git a/.gems/gems/memoizable-0.4.2/lib/memoizable/version.rb b/.gems/gems/memoizable-0.4.2/lib/memoizable/version.rb new file mode 100644 index 0000000..40c0e89 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/lib/memoizable/version.rb @@ -0,0 +1,8 @@ +# encoding: utf-8 + +module Memoizable + + # Gem version + VERSION = '0.4.2'.freeze + +end # Memoizable diff --git a/.gems/gems/memoizable-0.4.2/memoizable.gemspec b/.gems/gems/memoizable-0.4.2/memoizable.gemspec new file mode 100644 index 0000000..533e841 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/memoizable.gemspec @@ -0,0 +1,24 @@ +# encoding: utf-8 + +require File.expand_path('../lib/memoizable/version', __FILE__) + +Gem::Specification.new do |gem| + gem.name = 'memoizable' + gem.version = Memoizable::VERSION.dup + gem.authors = ['Dan Kubb', 'Erik Michaels-Ober'] + gem.email = ['dan.kubb@gmail.com', 'sferik@gmail.com'] + gem.description = 'Memoize method return values' + gem.summary = gem.description + gem.homepage = 'https://github.com/dkubb/memoizable' + gem.license = 'MIT' + + gem.require_paths = %w[lib] + gem.files = %w[CONTRIBUTING.md LICENSE.md README.md Rakefile memoizable.gemspec] + gem.files += Dir.glob('{lib,spec}/**/*.rb') + gem.test_files = Dir.glob('spec/{unit,integration}/**/*.rb') + gem.extra_rdoc_files = Dir.glob('**/*.md') + + gem.add_runtime_dependency('thread_safe', '~> 0.3', '>= 0.3.1') + + gem.add_development_dependency('bundler', '~> 1.5', '>= 1.5.3') +end diff --git a/.gems/gems/memoizable-0.4.2/spec/integration/serializable_spec.rb b/.gems/gems/memoizable-0.4.2/spec/integration/serializable_spec.rb new file mode 100644 index 0000000..acd194f --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/integration/serializable_spec.rb @@ -0,0 +1,34 @@ +# encoding: utf-8 + +require 'spec_helper' + +class Serializable + include Memoizable + + def random_number + rand(10000) + end + memoize :random_number +end + +describe 'A serializable object' do + let(:serializable) do + Serializable.new + end + + before do + serializable.random_number # Call the memoized method to trigger lazy memoization + end + + it 'is serializable with Marshal' do + expect { Marshal.dump(serializable) }.not_to raise_error + end + + it 'is deserializable with Marshal' do + serialized = Marshal.dump(serializable) + deserialized = Marshal.load(serialized) + + expect(deserialized).to be_an_instance_of(Serializable) + expect(deserialized.random_number).to eql(serializable.random_number) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/shared/call_super_shared_spec.rb b/.gems/gems/memoizable-0.4.2/spec/shared/call_super_shared_spec.rb new file mode 100644 index 0000000..9368180 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/shared/call_super_shared_spec.rb @@ -0,0 +1,23 @@ +# encoding: utf-8 + +shared_examples 'it calls super' do |method| + around do |example| + # Restore original method after each example + original = "original_#{method}" + superclass.class_eval do + alias_method original, method + example.call + undef_method method + alias_method method, original + end + end + + it "delegates to the superclass ##{method} method" do + # This is the most succinct approach I could think of to test whether the + # superclass method is called. All of the built-in rspec helpers did not + # seem to work for this. + called = false + superclass.class_eval { define_method(method) { |_| called = true } } + expect { subject }.to change { called }.from(false).to(true) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/shared/command_method_behavior.rb b/.gems/gems/memoizable-0.4.2/spec/shared/command_method_behavior.rb new file mode 100644 index 0000000..c62854d --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/shared/command_method_behavior.rb @@ -0,0 +1,7 @@ +# encoding: utf-8 + +shared_examples_for 'a command method' do + it 'returns self' do + should equal(object) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/spec_helper.rb b/.gems/gems/memoizable-0.4.2/spec/spec_helper.rb new file mode 100644 index 0000000..1bedf5f --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/spec_helper.rb @@ -0,0 +1,33 @@ +# encoding: utf-8 + +require 'simplecov' +require 'coveralls' + +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter +] + +SimpleCov.start do + command_name 'spec' + + add_filter 'config' + add_filter 'spec' + add_filter 'vendor' + + minimum_coverage 100 +end + +require 'memoizable' +require 'rspec' + +# Require spec support files and shared behavior +Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each do |file| + require file.chomp('.rb') +end + +RSpec.configure do |config| + config.expect_with :rspec do |expect_with| + expect_with.syntax = :expect + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/class_methods/included_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/class_methods/included_spec.rb new file mode 100644 index 0000000..4460f52 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/class_methods/included_spec.rb @@ -0,0 +1,18 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Memoizable, '.included' do + subject { object.class_eval { include Memoizable } } + + let(:object) { Class.new } + let(:superclass) { Module } + + it_behaves_like 'it calls super', :included + + it 'extends the descendant with module methods' do + subject + extended_modules = class << object; included_modules end + expect(extended_modules).to include(Memoizable::ModuleMethods) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/fixtures/classes.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/fixtures/classes.rb new file mode 100644 index 0000000..9b35180 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/fixtures/classes.rb @@ -0,0 +1,41 @@ +# encoding: utf-8 + +module Fixture + class Object + include Memoizable + + def required_arguments(foo) + end + + def optional_arguments(foo = nil) + end + + def test + 'test' + end + + def zero_arity + caller + end + + def one_arity(arg) + end + + def public_method + caller + end + + protected + + def protected_method + caller + end + + private + + def private_method + caller + end + + end # class Object +end # module Fixture diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/freeze_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/freeze_spec.rb new file mode 100644 index 0000000..6b776e9 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/freeze_spec.rb @@ -0,0 +1,27 @@ +# encoding: utf-8 + +require 'spec_helper' +require File.expand_path('../../fixtures/classes', __FILE__) + +describe Memoizable::InstanceMethods, '#freeze' do + subject { object.freeze } + + let(:described_class) { Class.new(Fixture::Object) } + + before do + described_class.memoize(:test) + end + + let(:object) { described_class.allocate } + + it_should_behave_like 'a command method' + + it 'freezes the object' do + expect { subject }.to change(object, :frozen?).from(false).to(true) + end + + it 'allows methods not yet called to be memoized' do + subject + expect(object.test).to be(object.test) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/memoize_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/memoize_spec.rb new file mode 100644 index 0000000..e75f4b3 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/instance_methods/memoize_spec.rb @@ -0,0 +1,40 @@ +# encoding: utf-8 + +require 'spec_helper' +require File.expand_path('../../fixtures/classes', __FILE__) + +describe Memoizable::InstanceMethods, '#memoize' do + subject { object.memoize(method => value) } + + let(:described_class) { Class.new(Fixture::Object) } + let(:object) { described_class.new } + let(:method) { :test } + + before do + described_class.memoize(method) + end + + context 'when the method is not memoized' do + let(:value) { String.new } + + it 'sets the memoized value for the method to the value' do + subject + expect(object.send(method)).to be(value) + end + + it_should_behave_like 'a command method' + end + + context 'when the method is already memoized' do + let(:value) { double } + let(:original) { nil } + + before do + object.memoize(method => original) + end + + it 'raises an exception' do + expect { subject }.to raise_error(ArgumentError) + end + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/memory_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/memory_spec.rb new file mode 100644 index 0000000..faf5a54 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/memory_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe Memoizable::Memory do + let(:memory) { Memoizable::Memory.new } + + context "serialization" do + let(:deserialized) { Marshal.load(Marshal.dump(memory)) } + + it 'is serializable with Marshal' do + expect { Marshal.dump(memory) }.not_to raise_error + end + + it 'is deserializable with Marshal' do + expect(deserialized).to be_an_instance_of(Memoizable::Memory) + end + + it 'mantains the same class of cache when deserialized' do + original_cache = memory.instance_variable_get(:@memory) + deserialized_cache = deserialized.instance_variable_get(:@memory) + + expect(deserialized_cache.class).to eql(original_cache.class) + end + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/call_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/call_spec.rb new file mode 100644 index 0000000..f81c1c7 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/call_spec.rb @@ -0,0 +1,93 @@ +# encoding: utf-8 + +require 'spec_helper' +require File.expand_path('../../fixtures/classes', __FILE__) + +describe Memoizable::MethodBuilder, '#call' do + subject { object.call } + + let(:object) { described_class.new(descendant, method_name, freezer) } + let(:freezer) { lambda { |object| object.freeze } } + let(:instance) { descendant.new } + + let(:descendant) do + Class.new do + include Memoizable + + def public_method + __method__.to_s + end + + def protected_method + __method__.to_s + end + protected :protected_method + + def private_method + __method__.to_s + end + private :private_method + end + end + + shared_examples_for 'Memoizable::MethodBuilder#call' do + it_should_behave_like 'a command method' + + it 'creates a method that is memoized' do + subject + expect(instance.send(method_name)).to be(instance.send(method_name)) + end + + it 'creates a method that returns the expected value' do + subject + expect(instance.send(method_name)).to eql(method_name.to_s) + end + + it 'creates a method that returns a frozen value' do + subject + expect(descendant.new.send(method_name)).to be_frozen + end + + it 'creates a method that does not accept a block' do + subject + expect { descendant.new.send(method_name) {} }.to raise_error( + described_class::BlockNotAllowedError, + "Cannot pass a block to #{descendant}##{method_name}, it is memoized" + ) + end + end + + context 'public method' do + let(:method_name) { :public_method } + + it_should_behave_like 'Memoizable::MethodBuilder#call' + + it 'creates a public memoized method' do + subject + expect(descendant).to be_public_method_defined(method_name) + end + end + + context 'protected method' do + let(:method_name) { :protected_method } + + it_should_behave_like 'Memoizable::MethodBuilder#call' + + it 'creates a protected memoized method' do + subject + expect(descendant).to be_protected_method_defined(method_name) + end + + end + + context 'private method' do + let(:method_name) { :private_method } + + it_should_behave_like 'Memoizable::MethodBuilder#call' + + it 'creates a private memoized method' do + subject + expect(descendant).to be_private_method_defined(method_name) + end + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/class_methods/new_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/class_methods/new_spec.rb new file mode 100644 index 0000000..7bb247c --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/class_methods/new_spec.rb @@ -0,0 +1,34 @@ +# encoding: utf-8 + +require 'spec_helper' +require File.expand_path('../../../fixtures/classes', __FILE__) + +describe Memoizable::MethodBuilder, '.new' do + subject { described_class.new(descendant, method_name, freezer) } + + let(:descendant) { Fixture::Object } + let(:freezer) { lambda { |object| object.freeze } } + + context 'with a zero arity method' do + let(:method_name) { :zero_arity } + + it { should be_instance_of(described_class) } + + it 'sets the original method' do + # original method is not memoized + method = subject.original_method.bind(descendant.new) + expect(method.call).to_not be(method.call) + end + end + + context 'with a one arity method' do + let(:method_name) { :one_arity } + + it 'raises an exception' do + expect { subject }.to raise_error( + described_class::InvalidArityError, + 'Cannot memoize Fixture::Object#one_arity, its arity is 1' + ) + end + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/original_method_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/original_method_spec.rb new file mode 100644 index 0000000..8d37b3f --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/method_builder/original_method_spec.rb @@ -0,0 +1,31 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Memoizable::MethodBuilder, '#original_method' do + subject { object.original_method } + + let(:object) { described_class.new(descendant, method_name, freezer) } + let(:method_name) { :foo } + let(:freezer) { lambda { |object| object.freeze } } + + let(:descendant) do + Class.new do + def initialize + @foo = 0 + end + + def foo + @foo += 1 + end + end + end + + it { should be_instance_of(UnboundMethod) } + + it 'returns the original method' do + # original method is not memoized + method = subject.bind(descendant.new) + expect(method.call).to_not be(method.call) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/included_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/included_spec.rb new file mode 100644 index 0000000..4ac2139 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/included_spec.rb @@ -0,0 +1,23 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Memoizable::ModuleMethods, '#included' do + subject { descendant.instance_exec(object) { |mod| include mod } } + + let(:object) { Module.new.extend(described_class) } + let(:descendant) { Class.new } + let(:superclass) { Module } + + before do + # Prevent Module.included from being called through inheritance + allow(Memoizable).to receive(:included) + end + + it_behaves_like 'it calls super', :included + + it 'includes Memoizable into the descendant' do + subject + expect(descendant.included_modules).to include(Memoizable) + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoize_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoize_spec.rb new file mode 100644 index 0000000..917f68b --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoize_spec.rb @@ -0,0 +1,123 @@ +# encoding: utf-8 + +require 'spec_helper' +require File.expand_path('../../fixtures/classes', __FILE__) + +shared_examples_for 'memoizes method' do + it 'memoizes the instance method' do + subject + instance = object.new + expect(instance.send(method)).to be(instance.send(method)) + end + + it 'creates a zero arity method', :unless => RUBY_VERSION == '1.8.7' do + subject + expect(object.new.method(method).arity).to be_zero + end + + context 'when the initializer calls the memoized method' do + before do + method = self.method + object.send(:define_method, :initialize) { send(method) } + end + + it 'allows the memoized method to be called within the initializer' do + subject + expect { object.new }.to_not raise_error + end + end +end + +describe Memoizable::ModuleMethods, '#memoize' do + subject { object.memoize(method) } + + let(:object) do + stub_const 'TestClass', Class.new(Fixture::Object) { + def some_state + Object.new + end + } + end + + context 'on method with required arguments' do + let(:method) { :required_arguments } + + it 'should raise error' do + expect { subject }.to raise_error( + Memoizable::MethodBuilder::InvalidArityError, + 'Cannot memoize TestClass#required_arguments, its arity is 1' + ) + end + end + + context 'on method with optional arguments' do + let(:method) { :optional_arguments } + + it 'should raise error' do + expect { subject }.to raise_error( + Memoizable::MethodBuilder::InvalidArityError, + 'Cannot memoize TestClass#optional_arguments, its arity is -1' + ) + end + end + + context 'memoized method that returns generated values' do + let(:method) { :some_state } + + it_should_behave_like 'a command method' + it_should_behave_like 'memoizes method' + + it 'creates a method that returns a frozen value' do + subject + expect(object.new.send(method)).to be_frozen + end + end + + context 'public method' do + let(:method) { :public_method } + + it_should_behave_like 'a command method' + it_should_behave_like 'memoizes method' + + it 'is still a public method' do + should be_public_method_defined(method) + end + + it 'creates a method that returns a frozen value' do + subject + expect(object.new.send(method)).to be_frozen + end + end + + context 'protected method' do + let(:method) { :protected_method } + + it_should_behave_like 'a command method' + it_should_behave_like 'memoizes method' + + it 'is still a protected method' do + should be_protected_method_defined(method) + end + + it 'creates a method that returns a frozen value' do + subject + expect(object.new.send(method)).to be_frozen + end + end + + context 'private method' do + let(:method) { :private_method } + + it_should_behave_like 'a command method' + it_should_behave_like 'memoizes method' + + it 'is still a private method' do + should be_private_method_defined(method) + end + + it 'creates a method that returns a frozen value' do + subject + expect(object.new.send(method)).to be_frozen + end + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoized_predicate_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoized_predicate_spec.rb new file mode 100644 index 0000000..c54674d --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/memoized_predicate_spec.rb @@ -0,0 +1,28 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Memoizable::ModuleMethods, '#memoized?' do + let(:object) do + Class.new do + include Memoizable + def foo + end + memoize :foo + end + end + + subject { object.memoized?(name) } + + context 'with memoized method' do + let(:name) { :foo } + + it { should be(true) } + end + + context 'with non memoized method' do + let(:name) { :bar } + + it { should be(false) } + end +end diff --git a/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/unmemoized_instance_method_spec.rb b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/unmemoized_instance_method_spec.rb new file mode 100644 index 0000000..0f6fb98 --- /dev/null +++ b/.gems/gems/memoizable-0.4.2/spec/unit/memoizable/module_methods/unmemoized_instance_method_spec.rb @@ -0,0 +1,43 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe Memoizable::ModuleMethods, '#unmemoized_instance_method' do + subject { object.unmemoized_instance_method(name) } + + let(:object) do + Class.new do + include Memoizable + + def initialize + @foo = 0 + end + + def foo + @foo += 1 + end + + memoize :foo + end + end + + context 'when the method was memoized' do + let(:name) { :foo } + + it { should be_instance_of(UnboundMethod) } + + it 'returns the original method' do + # original method is not memoized + method = subject.bind(object.new) + expect(method.call).to_not be(method.call) + end + end + + context 'when the method was not memoized' do + let(:name) { :bar } + + it 'raises an exception' do + expect { subject }.to raise_error(NameError, 'No method bar is memoized') + end + end +end diff --git a/.gems/gems/multipart-post-2.0.0/.gitignore b/.gems/gems/multipart-post-2.0.0/.gitignore new file mode 100644 index 0000000..c02a141 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/.gitignore @@ -0,0 +1,6 @@ +doc +pkg +*~ +*.swo +*.swp +/Gemfile.lock diff --git a/.gems/gems/multipart-post-2.0.0/.travis.yml b/.gems/gems/multipart-post-2.0.0/.travis.yml new file mode 100644 index 0000000..e1ea1fe --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/.travis.yml @@ -0,0 +1,7 @@ +rvm: + - 1.9.3 + - 2.0.0 + - jruby +branches: + only: + - master diff --git a/.gems/gems/multipart-post-2.0.0/Gemfile b/.gems/gems/multipart-post-2.0.0/Gemfile new file mode 100644 index 0000000..e55151b --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/Gemfile @@ -0,0 +1,14 @@ +source 'https://rubygems.org' +gemspec + +platforms :mri_19 do + gem 'ruby-debug19' +end + +platforms :mri_18 do + gem 'ruby-debug' +end + +group :development, :test do + gem 'rake' +end diff --git a/.gems/gems/multipart-post-2.0.0/History.txt b/.gems/gems/multipart-post-2.0.0/History.txt new file mode 100644 index 0000000..64b1e38 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/History.txt @@ -0,0 +1,60 @@ +=== 2.0.0 / 2013-12-21 + +- Drop Ruby 1.8 compatibility +- GH #21: Fix FilePart length calculation for Ruby 1.9 when filename contains + multibyte characters (hexfet) +- GH #20: Ensure upload responds to both #content_type and #original_filename + (Steven Davidovitz) +- GH #31: Support setting headers on any part of the request (Socrates Vicente) +- GH #30: Support array values for params (Gustav Ernberg) +- GH #32: Fix respond_to? signature (Leo Cassarani) +- GH #33: Update README to markdown (Jagtesh Chadha) +- GH #35: Improved handling of array-type parameters (Steffen Grunwald) + +=== 1.2.0 / 2013-02-25 + +- #25: Ruby 2 compatibility (thanks mislav) + +=== 1.1.5 / 2012-02-12 + +- Fix length/bytesize of parts in 1.9 (#7, #14) (Jason Moore) +- Allow CompositeIO objects to be re-read by rewinding, like other IO + objects. (Luke Redpath) + +=== 1.1.4 / 2011-11-23 + +- Non-functional changes in release (switch to Bundler gem tasks) + +=== 1.1.3 / 2011-07-25 + +- More configurable header specification for parts (Gerrit Riessen) + +=== 1.1.2 / 2011-05-24 + +- Fix CRLF file part miscalculation (Johannes Wagener) +- Fix Epilogue CRLF issue (suggestion by Neil Spring) + +=== 1.1.1 / 2011-05-13 + +- GH# 9: Fixed Ruby 1.9.2 StringIO bug (thanks Alex Koppel) + +=== 1.1.0 / 2011-01-11 + +- API CHANGE: UploadIO.convert! removed in favor of UploadIO.new + (Jeff Hodges) + +=== 1.0.1 / 2010-04-27 + +- Doc updates, make gemspec based on more modern Rubygems + +=== 1.0 / 2009-02-12 + +- Many fixes from mlooney, seems to work now. Putting the 0.9 seal of + approval on it. + +=== 0.1 / 2008-08-12 + +* 1 major enhancement + + * Birthday! + diff --git a/.gems/gems/multipart-post-2.0.0/Manifest.txt b/.gems/gems/multipart-post-2.0.0/Manifest.txt new file mode 100644 index 0000000..109d8f0 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/Manifest.txt @@ -0,0 +1,9 @@ +lib/composite_io.rb +lib/multipartable.rb +lib/parts.rb +lib/net/http/post/multipart.rb +Manifest.txt +Rakefile +README.txt +test/test_composite_io.rb +test/net/http/post/test_multipart.rb diff --git a/.gems/gems/multipart-post-2.0.0/README.md b/.gems/gems/multipart-post-2.0.0/README.md new file mode 100644 index 0000000..fc7eae1 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/README.md @@ -0,0 +1,77 @@ +## multipart-post + +* http://github.com/nicksieger/multipart-post + +![build status](https://travis-ci.org/nicksieger/multipart-post.png) + +#### DESCRIPTION: + +Adds a streamy multipart form post capability to Net::HTTP. Also +supports other methods besides POST. + +#### FEATURES/PROBLEMS: + +* Appears to actually work. A good feature to have. +* Encapsulates posting of file/binary parts and name/value parameter parts, similar to + most browsers' file upload forms. +* Provides an UploadIO helper class to prepare IO objects for inclusion in the params + hash of the multipart post object. + +#### SYNOPSIS: + + require 'net/http/post/multipart' + + url = URI.parse('http://www.example.com/upload') + File.open("./image.jpg") do |jpg| + req = Net::HTTP::Post::Multipart.new url.path, + "file" => UploadIO.new(jpg, "image/jpeg", "image.jpg") + res = Net::HTTP.start(url.host, url.port) do |http| + http.request(req) + end + end + +To post multiple files or attachments, simply include multiple parameters with +UploadIO values: + + require 'net/http/post/multipart' + + url = URI.parse('http://www.example.com/upload') + req = Net::HTTP::Post::Multipart.new url.path, + "file1" => UploadIO.new(File.new("./image.jpg"), "image/jpeg", "image.jpg"), + "file2" => UploadIO.new(File.new("./image2.jpg"), "image/jpeg", "image2.jpg") + res = Net::HTTP.start(url.host, url.port) do |http| + http.request(req) + end + +#### REQUIREMENTS: + +None + +#### INSTALL: + + gem install multipart-post + +#### LICENSE: + +(The MIT License) + +Copyright (c) 2007-2013 Nick Sieger + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/multipart-post-2.0.0/Rakefile b/.gems/gems/multipart-post-2.0.0/Rakefile new file mode 100644 index 0000000..dd85431 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/Rakefile @@ -0,0 +1,9 @@ +require "bundler/gem_tasks" + +task :default => :test + +require 'rake/testtask' +Rake::TestTask.new do |t| + t.libs << "test" + t.test_files = FileList['test/**/test*.rb'] +end diff --git a/.gems/gems/multipart-post-2.0.0/lib/composite_io.rb b/.gems/gems/multipart-post-2.0.0/lib/composite_io.rb new file mode 100644 index 0000000..4ba7cf5 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/lib/composite_io.rb @@ -0,0 +1,108 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +# Concatenate together multiple IO objects into a single, composite IO object +# for purposes of reading as a single stream. +# +# Usage: +# +# crio = CompositeReadIO.new(StringIO.new('one'), StringIO.new('two'), StringIO.new('three')) +# puts crio.read # => "onetwothree" +# +class CompositeReadIO + # Create a new composite-read IO from the arguments, all of which should + # respond to #read in a manner consistent with IO. + def initialize(*ios) + @ios = ios.flatten + @index = 0 + end + + # Read from IOs in order until `length` bytes have been received. + def read(length = nil, outbuf = nil) + got_result = false + outbuf = outbuf ? outbuf.replace("") : "" + + while io = current_io + if result = io.read(length) + got_result ||= !result.nil? + result.force_encoding("BINARY") if result.respond_to?(:force_encoding) + outbuf << result + length -= result.length if length + break if length == 0 + end + advance_io + end + (!got_result && length) ? nil : outbuf + end + + def rewind + @ios.each { |io| io.rewind } + @index = 0 + end + + private + + def current_io + @ios[@index] + end + + def advance_io + @index += 1 + end +end + +# Convenience methods for dealing with files and IO that are to be uploaded. +class UploadIO + # Create an upload IO suitable for including in the params hash of a + # Net::HTTP::Post::Multipart. + # + # Can take two forms. The first accepts a filename and content type, and + # opens the file for reading (to be closed by finalizer). + # + # The second accepts an already-open IO, but also requires a third argument, + # the filename from which it was opened (particularly useful/recommended if + # uploading directly from a form in a framework, which often save the file to + # an arbitrarily named RackMultipart file in /tmp). + # + # Usage: + # + # UploadIO.new("file.txt", "text/plain") + # UploadIO.new(file_io, "text/plain", "file.txt") + # + attr_reader :content_type, :original_filename, :local_path, :io, :opts + + def initialize(filename_or_io, content_type, filename = nil, opts = {}) + io = filename_or_io + local_path = "" + if io.respond_to? :read + # in Ruby 1.9.2, StringIOs no longer respond to path + # (since they respond to :length, so we don't need their local path, see parts.rb:41) + local_path = filename_or_io.respond_to?(:path) ? filename_or_io.path : "local.path" + else + io = File.open(filename_or_io) + local_path = filename_or_io + end + filename ||= local_path + + @content_type = content_type + @original_filename = File.basename(filename) + @local_path = local_path + @io = io + @opts = opts + end + + def self.convert!(io, content_type, original_filename, local_path) + raise ArgumentError, "convert! has been removed. You must now wrap IOs using:\nUploadIO.new(filename_or_io, content_type, filename=nil)\nPlease update your code." + end + + def method_missing(*args) + @io.send(*args) + end + + def respond_to?(meth, include_all = false) + @io.respond_to?(meth, include_all) || super(meth, include_all) + end +end diff --git a/.gems/gems/multipart-post-2.0.0/lib/multipart_post.rb b/.gems/gems/multipart-post-2.0.0/lib/multipart_post.rb new file mode 100644 index 0000000..76540a8 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/lib/multipart_post.rb @@ -0,0 +1,9 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +module MultipartPost + VERSION = "2.0.0" +end diff --git a/.gems/gems/multipart-post-2.0.0/lib/multipartable.rb b/.gems/gems/multipart-post-2.0.0/lib/multipartable.rb new file mode 100644 index 0000000..28fa41e --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/lib/multipartable.rb @@ -0,0 +1,29 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'parts' + module Multipartable + DEFAULT_BOUNDARY = "-----------RubyMultipartPost" + def initialize(path, params, headers={}, boundary = DEFAULT_BOUNDARY) + headers = headers.clone # don't want to modify the original variable + parts_headers = headers.delete(:parts) || {} + super(path, headers) + parts = params.map do |k,v| + case v + when Array + v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) } + else + Parts::Part.new(boundary, k, v, parts_headers[k]) + end + end.flatten + parts << Parts::EpiloguePart.new(boundary) + ios = parts.map {|p| p.to_io } + self.set_content_type(headers["Content-Type"] || "multipart/form-data", + { "boundary" => boundary }) + self.content_length = parts.inject(0) {|sum,i| sum + i.length } + self.body_stream = CompositeReadIO.new(*ios) + end + end diff --git a/.gems/gems/multipart-post-2.0.0/lib/net/http/post/multipart.rb b/.gems/gems/multipart-post-2.0.0/lib/net/http/post/multipart.rb new file mode 100644 index 0000000..7570582 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/lib/net/http/post/multipart.rb @@ -0,0 +1,27 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'net/http' +require 'stringio' +require 'cgi' +require 'composite_io' +require 'multipartable' +require 'parts' + +module Net #:nodoc: + class HTTP #:nodoc: + class Put + class Multipart < Put + include Multipartable + end + end + class Post #:nodoc: + class Multipart < Post + include Multipartable + end + end + end +end diff --git a/.gems/gems/multipart-post-2.0.0/lib/parts.rb b/.gems/gems/multipart-post-2.0.0/lib/parts.rb new file mode 100644 index 0000000..c06cbd9 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/lib/parts.rb @@ -0,0 +1,96 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +module Parts + module Part #:nodoc: + def self.new(boundary, name, value, headers = {}) + headers ||= {} # avoid nil values + if file?(value) + FilePart.new(boundary, name, value, headers) + else + ParamPart.new(boundary, name, value, headers) + end + end + + def self.file?(value) + value.respond_to?(:content_type) && value.respond_to?(:original_filename) + end + + def length + @part.length + end + + def to_io + @io + end + end + + class ParamPart + include Part + def initialize(boundary, name, value, headers = {}) + @part = build_part(boundary, name, value, headers) + @io = StringIO.new(@part) + end + + def length + @part.bytesize + end + + def build_part(boundary, name, value, headers = {}) + part = '' + part << "--#{boundary}\r\n" + part << "Content-Disposition: form-data; name=\"#{name.to_s}\"\r\n" + part << "Content-Type: #{headers["Content-Type"]}\r\n" if headers["Content-Type"] + part << "\r\n" + part << "#{value}\r\n" + end + end + + # Represents a part to be filled from file IO. + class FilePart + include Part + attr_reader :length + def initialize(boundary, name, io, headers = {}) + file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path) + @head = build_head(boundary, name, io.original_filename, io.content_type, file_length, + io.respond_to?(:opts) ? io.opts.merge(headers) : headers) + @foot = "\r\n" + @length = @head.bytesize + file_length + @foot.length + @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot)) + end + + def build_head(boundary, name, filename, type, content_len, opts = {}, headers = {}) + trans_encoding = opts["Content-Transfer-Encoding"] || "binary" + content_disposition = opts["Content-Disposition"] || "form-data" + + part = '' + part << "--#{boundary}\r\n" + part << "Content-Disposition: #{content_disposition}; name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n" + part << "Content-Length: #{content_len}\r\n" + if content_id = opts["Content-ID"] + part << "Content-ID: #{content_id}\r\n" + end + + if headers["Content-Type"] != nil + part << "Content-Type: " + headers["Content-Type"] + "\r\n" + else + part << "Content-Type: #{type}\r\n" + end + + part << "Content-Transfer-Encoding: #{trans_encoding}\r\n" + part << "\r\n" + end + end + + # Represents the epilogue or closing boundary. + class EpiloguePart + include Part + def initialize(boundary) + @part = "--#{boundary}--\r\n\r\n" + @io = StringIO.new(@part) + end + end +end diff --git a/.gems/gems/multipart-post-2.0.0/multipart-post.gemspec b/.gems/gems/multipart-post-2.0.0/multipart-post.gemspec new file mode 100644 index 0000000..6954f09 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/multipart-post.gemspec @@ -0,0 +1,22 @@ +# -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) +require "multipart_post" + +Gem::Specification.new do |s| + s.name = "multipart-post" + s.version = MultipartPost::VERSION + s.authors = ["Nick Sieger"] + s.email = ["nick@nicksieger.com"] + s.homepage = "https://github.com/nicksieger/multipart-post" + s.summary = %q{A multipart form post accessory for Net::HTTP.} + s.license = "MIT" + s.description = %q{Use with Net::HTTP to do multipart form posts. IO values that have #content_type, #original_filename, and #local_path will be posted as a binary file.} + + s.rubyforge_project = "caldersphere" + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.rdoc_options = ["--main", "README.md", "-SHN", "-f", "darkfish"] + s.require_paths = ["lib"] +end diff --git a/.gems/gems/multipart-post-2.0.0/test/multibyte.txt b/.gems/gems/multipart-post-2.0.0/test/multibyte.txt new file mode 100644 index 0000000..24a84b0 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/test/multibyte.txt @@ -0,0 +1 @@ +ファイル diff --git a/.gems/gems/multipart-post-2.0.0/test/net/http/post/test_multipart.rb b/.gems/gems/multipart-post-2.0.0/test/net/http/post/test_multipart.rb new file mode 100644 index 0000000..c127e0a --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/test/net/http/post/test_multipart.rb @@ -0,0 +1,110 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'net/http/post/multipart' +require 'test/unit' + +class Net::HTTP::Post::MultiPartTest < Test::Unit::TestCase + TEMP_FILE = "temp.txt" + + HTTPPost = Struct.new("HTTPPost", :content_length, :body_stream, :content_type) + HTTPPost.module_eval do + def set_content_type(type, params = {}) + self.content_type = type + params.map{|k,v|"; #{k}=#{v}"}.join('') + end + end + + def teardown + File.delete(TEMP_FILE) rescue nil + end + + def test_form_multipart_body + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) + end + def test_form_multipart_body_put + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Put::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) + end + + def test_form_multipart_body_with_stringio + @io = StringIO.new("1234567890") + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', :file => @io) + end + + def test_form_multiparty_body_with_parts_headers + @io = StringIO.new("1234567890") + @io = UploadIO.new @io, "text/plain", TEMP_FILE + parts = { :text => 'bar', :file => @io } + headers = { + :parts => { + :text => { "Content-Type" => "part/type" }, + :file => { "Content-Transfer-Encoding" => "part-encoding" } + } + } + + request = Net::HTTP::Post::Multipart.new("/foo/bar", parts, headers) + assert_results request + assert_additional_headers_added(request, headers[:parts]) + end + + def test_form_multipart_body_with_array_value + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + params = {:foo => ['bar', 'quux'], :file => @io} + headers = { :parts => { + :foo => { "Content-Type" => "application/json; charset=UTF-8" } } } + post = Net::HTTP::Post::Multipart.new("/foo/bar", params, headers, + Net::HTTP::Post::Multipart::DEFAULT_BOUNDARY) + + assert post.content_length && post.content_length > 0 + assert post.body_stream + + body = post.body_stream.read + assert_equal 2, body.lines.grep(/name="foo"/).length + assert body =~ /Content-Type: application\/json; charset=UTF-8/, body + end + + def test_form_multipart_body_with_arrayparam + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + @io = File.open(TEMP_FILE) + @io = UploadIO.new @io, "text/plain", TEMP_FILE + assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :multivalueParam => ['bar','bah'], :file => @io) + end + + def assert_results(post) + assert post.content_length && post.content_length > 0 + assert post.body_stream + assert_equal "multipart/form-data; boundary=#{Multipartable::DEFAULT_BOUNDARY}", post['content-type'] + body = post.body_stream.read + boundary_regex = Regexp.quote Multipartable::DEFAULT_BOUNDARY + assert body =~ /1234567890/ + # ensure there is at least one boundary + assert body =~ /^--#{boundary_regex}\r\n/ + # ensure there is an epilogue + assert body =~ /^--#{boundary_regex}--\r\n/ + assert body =~ /text\/plain/ + if (body =~ /multivalueParam/) + assert_equal 2, body.scan(/^.*multivalueParam.*$/).size + end + end + + def assert_additional_headers_added(post, parts_headers) + post.body_stream.rewind + body = post.body_stream.read + parts_headers.each do |part, headers| + headers.each do |k,v| + assert body =~ /#{k}: #{v}/ + end + end + end +end diff --git a/.gems/gems/multipart-post-2.0.0/test/test_composite_io.rb b/.gems/gems/multipart-post-2.0.0/test/test_composite_io.rb new file mode 100644 index 0000000..6e8a193 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/test/test_composite_io.rb @@ -0,0 +1,115 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'composite_io' +require 'stringio' +require 'test/unit' +require 'timeout' + +class CompositeReadIOTest < Test::Unit::TestCase + def setup + @io = CompositeReadIO.new(CompositeReadIO.new(StringIO.new('the '), StringIO.new('quick ')), + StringIO.new('brown '), StringIO.new('fox')) + end + + def test_full_read_from_several_ios + assert_equal 'the quick brown fox', @io.read + end + + unless RUBY_VERSION < '1.9' + def test_read_from_multibyte + utf8 = File.open(File.dirname(__FILE__)+'/multibyte.txt') + binary = StringIO.new("\x86") + @io = CompositeReadIO.new(binary,utf8) + + expect = "\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\n" + expect.force_encoding('BINARY') if expect.respond_to?(:force_encoding) + assert_equal expect, @io.read + end + end + + def test_partial_read + assert_equal 'the quick', @io.read(9) + end + + def test_partial_read_to_boundary + assert_equal 'the quick ', @io.read(10) + end + + def test_read_with_size_larger_than_available + assert_equal 'the quick brown fox', @io.read(32) + end + + def test_read_into_buffer + buf = '' + @io.read(nil, buf) + assert_equal 'the quick brown fox', buf + end + + def test_multiple_reads + assert_equal 'the ', @io.read(4) + assert_equal 'quic', @io.read(4) + assert_equal 'k br', @io.read(4) + assert_equal 'own ', @io.read(4) + assert_equal 'fox', @io.read(4) + end + + def test_read_after_end + @io.read + assert_equal "", @io.read + end + + def test_read_after_end_with_amount + @io.read(32) + assert_equal nil, @io.read(32) + end + + def test_second_full_read_after_rewinding + @io.read + @io.rewind + assert_equal 'the quick brown fox', @io.read + end + + def test_convert_error + assert_raises(ArgumentError) { + UploadIO.convert!('tmp.txt', 'text/plain', 'tmp.txt', 'tmp.txt') + } + end + + ## FIXME excluding on JRuby due to + ## http://jira.codehaus.org/browse/JRUBY-7109 + if IO.respond_to?(:copy_stream) && !defined?(JRUBY_VERSION) + def test_compatible_with_copy_stream + target_io = StringIO.new + Timeout.timeout(1) do + IO.copy_stream(@io, target_io) + end + assert_equal "the quick brown fox", target_io.string + end + end + + def test_empty + io = CompositeReadIO.new + assert_equal "", io.read + end + + def test_empty_limited + io = CompositeReadIO.new + assert_nil io.read(1) + end + + def test_empty_parts + io = CompositeReadIO.new(StringIO.new, StringIO.new('the '), StringIO.new, StringIO.new('quick')) + assert_equal "the", io.read(3) + assert_equal " qu", io.read(3) + assert_equal "ick", io.read(4) + end + + def test_all_empty_parts + io = CompositeReadIO.new(StringIO.new, StringIO.new) + assert_nil io.read(1) + end +end diff --git a/.gems/gems/multipart-post-2.0.0/test/test_parts.rb b/.gems/gems/multipart-post-2.0.0/test/test_parts.rb new file mode 100644 index 0000000..33c1e39 --- /dev/null +++ b/.gems/gems/multipart-post-2.0.0/test/test_parts.rb @@ -0,0 +1,86 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'test/unit' + +require 'parts' +require 'stringio' +require 'composite_io' +require 'tempfile' + + +MULTIBYTE = File.dirname(__FILE__)+'/multibyte.txt' +TEMP_FILE = "temp.txt" + +module AssertPartLength + def assert_part_length(part) + bytes = part.to_io.read + bytesize = bytes.respond_to?(:bytesize) ? bytes.bytesize : bytes.length + assert_equal bytesize, part.length + end +end + +class PartTest < Test::Unit::TestCase + def setup + @string_with_content_type = Class.new(String) do + def content_type; 'application/data'; end + end + end + + def test_file_with_upload_io + assert Parts::Part.file?(UploadIO.new(__FILE__, "text/plain")) + end + + def test_file_with_modified_string + assert !Parts::Part.file?(@string_with_content_type.new("Hello")) + end + + def test_new_with_modified_string + assert_kind_of Parts::ParamPart, + Parts::Part.new("boundary", "multibyte", @string_with_content_type.new("Hello")) + end +end + +class FilePartTest < Test::Unit::TestCase + include AssertPartLength + + def setup + File.open(TEMP_FILE, "w") {|f| f << "1234567890"} + io = UploadIO.new(TEMP_FILE, "text/plain") + @part = Parts::FilePart.new("boundary", "afile", io) + end + + def teardown + File.delete(TEMP_FILE) rescue nil + end + + def test_correct_length + assert_part_length @part + end + + def test_multibyte_file_length + assert_part_length Parts::FilePart.new("boundary", "multibyte", UploadIO.new(MULTIBYTE, "text/plain")) + end + + def test_multibyte_filename + name = File.read(MULTIBYTE, 300) + file = Tempfile.new(name.respond_to?(:force_encoding) ? name.force_encoding("UTF-8") : name) + assert_part_length Parts::FilePart.new("boundary", "multibyte", UploadIO.new(file, "text/plain")) + file.close + end +end + +class ParamPartTest < Test::Unit::TestCase + include AssertPartLength + + def setup + @part = Parts::ParamPart.new("boundary", "multibyte", File.read(MULTIBYTE)) + end + + def test_correct_length + assert_part_length @part + end +end diff --git a/.gems/gems/naught-1.0.0/.gitignore b/.gems/gems/naught-1.0.0/.gitignore new file mode 100644 index 0000000..a2890cc --- /dev/null +++ b/.gems/gems/naught-1.0.0/.gitignore @@ -0,0 +1,23 @@ +*.gem +*.rbc +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +/naught.org +/naught.html +/bin +/TAGS +/gems.tags +/tags diff --git a/.gems/gems/naught-1.0.0/.rspec b/.gems/gems/naught-1.0.0/.rspec new file mode 100644 index 0000000..0912718 --- /dev/null +++ b/.gems/gems/naught-1.0.0/.rspec @@ -0,0 +1,2 @@ +--color +--order random diff --git a/.gems/gems/naught-1.0.0/.rubocop.yml b/.gems/gems/naught-1.0.0/.rubocop.yml new file mode 100644 index 0000000..80bed14 --- /dev/null +++ b/.gems/gems/naught-1.0.0/.rubocop.yml @@ -0,0 +1,74 @@ +AllCops: + Includes: + - 'Gemfile' + - 'Rakefile' + - 'naught.gemspec' + +# Avoid long parameter lists +ParameterLists: + Max: 4 + CountKeywordArgs: true + +ClassLength: + Max: 144 # TODO: Lower to 100 + +MethodLength: + CountComments: false + Max: 21 # TODO: Lower to 15 + +# Avoid more than `Max` levels of nesting. +BlockNesting: + Max: 2 + +# Align with the style guide. +CollectionMethods: + PreferredMethods: + map: 'collect' + reduce: 'inject' + find: 'detect' + find_all: 'select' + +# Limit line length +LineLength: + Enabled: false + +# Disable documentation checking until a class needs to be documented once +Documentation: + Enabled: false + +# Enforce Ruby 1.8-compatible hash syntax +HashSyntax: + EnforcedStyle: hash_rockets + +# No spaces inside hash literals +SpaceInsideHashLiteralBraces: + EnforcedStyle: no_space + +# Allow dots at the end of lines +DotPosition: + Enabled: false + +# Don't require magic comment at the top of every file +Encoding: + Enabled: false + +EmptyLinesAroundAccessModifier: + Enabled: true + +# Align ends correctly +EndAlignment: + AlignWith: variable + +# Indentation of when/else +CaseIndentation: + IndentWhenRelativeTo: end + IndentOneStep: false + +Lambda: + Enabled: false + +MethodName: + Enabled: false + +ClassVars: + Enabled: false diff --git a/.gems/gems/naught-1.0.0/.travis.yml b/.gems/gems/naught-1.0.0/.travis.yml new file mode 100644 index 0000000..3cc61e6 --- /dev/null +++ b/.gems/gems/naught-1.0.0/.travis.yml @@ -0,0 +1,20 @@ +before_install: + - gem update --system 2.1.11 + - gem --version +bundler_args: --without development +language: ruby +rvm: + - 1.8.7 + - 1.9.2 + - 1.9.3 + - 2.0.0 + - 2.1.0 + - jruby + - jruby-head + - rbx + - ruby-head +matrix: + allow_failures: + - rvm: jruby-head + - rvm: ruby-head + fast_finish: true diff --git a/.gems/gems/naught-1.0.0/Changelog.md b/.gems/gems/naught-1.0.0/Changelog.md new file mode 100644 index 0000000..352617d --- /dev/null +++ b/.gems/gems/naught-1.0.0/Changelog.md @@ -0,0 +1,12 @@ +## 1.0.0 + + - [Replace `::BasicObject` with `Naught::BasicObject`](https://github.com/avdi/naught/commit/8defad0bf9eb65e33054bf0a6e9c625c87c3e6df) + - [Delegate explicit conversions to nil instead of defining them explicitly](https://github.com/avdi/naught/commit/85c195de80ed56993b88f47e09112c903a92a167) + - Add support for (and run tests on) Ruby 1.8, 1.9, 2.0, 2.1, JRuby, and Rubinius + +## 0.0.3 + +Features: + + - New "pebble" mode (Guilherme Carvalho) + diff --git a/.gems/gems/naught-1.0.0/Gemfile b/.gems/gems/naught-1.0.0/Gemfile new file mode 100644 index 0000000..5e92b9a --- /dev/null +++ b/.gems/gems/naught-1.0.0/Gemfile @@ -0,0 +1,31 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in naught.gemspec +gemspec + +gem 'rake' + +group :development do + platforms :ruby_19, :ruby_20, :ruby_21 do + gem 'guard' + gem 'guard-bundler' + gem 'guard-rspec' + end + gem 'pry' + gem 'pry-rescue' +end + +group :test do + gem 'coveralls', :require => false + gem 'json', :platforms => [:jruby, :rbx, :ruby_18, :ruby_19] + gem 'libnotify' + gem 'mime-types', '~> 1.25', :platforms => [:jruby, :ruby_18] + gem 'rspec', '>= 2.14' + gem 'rubocop', '>= 0.16', :platforms => [:ruby_19, :ruby_20, :ruby_21] +end + +platforms :rbx do + gem 'racc' + gem 'rubinius-coverage', '~> 2.0' + gem 'rubysl', '~> 2.0' +end diff --git a/.gems/gems/naught-1.0.0/Guardfile b/.gems/gems/naught-1.0.0/Guardfile new file mode 100644 index 0000000..24e51c8 --- /dev/null +++ b/.gems/gems/naught-1.0.0/Guardfile @@ -0,0 +1,15 @@ +guard 'bundler' do + watch('Gemfile') + watch(/^.+\.gemspec/) +end + +guard :rspec, cli: '-fs --color --order rand' do + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { "spec" } +end + +guard 'ctags-bundler', emacs: true, src_path: ["lib", "spec/support"] do + watch(/^(lib|spec\/support)\/.*\.rb$/) + watch('Gemfile.lock') +end diff --git a/.gems/gems/naught-1.0.0/LICENSE.txt b/.gems/gems/naught-1.0.0/LICENSE.txt new file mode 100644 index 0000000..ff598db --- /dev/null +++ b/.gems/gems/naught-1.0.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Avdi Grimm + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/naught-1.0.0/README.markdown b/.gems/gems/naught-1.0.0/README.markdown new file mode 100644 index 0000000..868b090 --- /dev/null +++ b/.gems/gems/naught-1.0.0/README.markdown @@ -0,0 +1,436 @@ +[![Build Status](https://travis-ci.org/avdi/naught.png?branch=master)](https://travis-ci.org/avdi/naught) +[![Code Climate](https://codeclimate.com/github/avdi/naught.png)](https://codeclimate.com/github/avdi/naught) +[![Coverage Status](https://coveralls.io/repos/avdi/naught/badge.png?branch=master)](https://coveralls.io/r/avdi/naught?branch=master) +[![Gem Version](https://badge.fury.io/rb/naught.png)](http://badge.fury.io/rb/naught) + +A quick intro to Naught +------------------------- + +#### What's all this now then? + +Naught is a toolkit for building [Null +Objects](http://en.wikipedia.org/wiki/Null_Object_pattern) in Ruby. + +#### What's that supposed to mean? + +Null Objects can make your code more +[confident](http://confidentruby.com). + +Here's a method that's not very sure of itself. + +```ruby +class Geordi + def make_it_so(logger=nil) + logger && logger.info("Reversing the flux phase capacitance!") + logger && logger.info("Bounding a tachyon particle beam off of Data's cat!") + logger && logger.warn("Warning, bogon levels are rising!") + end +end +``` + +Now, observe as we give it a dash of confidence with the Null Object +pattern! + +```ruby +class NullLogger + def debug(*); end + def info(*); end + def warn(*); end + def error(*); end + def fatal(*); end +end + +class Geordi + def make_it_so(logger=NullLogger.new) + logger.info "Reversing the flux phase capacitance!" + logger.info "Bounding a tachyon particle beam off of Data's cat!" + logger.warn "Warning, bogon levels are rising!" + end +end +``` + +By providing a `NullLogger` which implements [some of] the `Logger` +interface as no-op methods, we've gotten rid of those unsightly `&&` +operators. + +#### That was simple enough. Why do I need a library for it? + +You don't! The Null Object pattern is a very simple one at its core. + +#### And yet here we are… + +Yes. While you don't *need* a Null Object library, this one offers some +conveniences you probably won't find elsewhere. + +But there's an even more important reason I wrote this library. In the +immortal last words of James T. Kirk: "It was… *fun!*" + +#### OK, so how do I use this thing? + +Well, what would you like to do? + +#### I dunno, gimme an object that responds to any message with nil + +Sure thing! + +```ruby +require 'naught' + +NullObject = Naught.build + +null = NullObject.new +null.foo # => nil +null.bar # => nil +``` + +#### That was… weird. What's with this "build" business? + +Naught is a *toolkit* for building null object classes. It is not a +one-size-fits-all solution. + +What else can I make for you? + +#### How about a "black hole" null object that supports infinite chaining of methods? + +OK. + +```ruby +require 'naught' + +BlackHole = Naught.build do |config| + config.black_hole +end + +null = BlackHole.new +null.foo # => +null.foo.bar.baz # => +null << "hello" << "world" # => +``` + +#### What's that "config" thing? + +That's what you use to customize the generated class to your +liking. Internally, Naught uses the [Builder +Pattern](http://en.wikipedia.org/wiki/Builder_pattern) to make this work.. + +#### Whatever. What if I want a null object that has conversions to Integer, String, etc. using sensible conversions to "zero values"? + +We can do that. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + config.define_explicit_conversions +end + +null = NullObject.new + +null.to_s # => "" +null.to_i # => 0 +null.to_f # => 0.0 +null.to_a # => [] +null.to_h # => {} +null.to_c # => (0+0i) +null.to_r # => (0/1) +``` + +#### Ah, but what about implicit conversions such as `#to_str`? Like what if I want a null object that implicitly splats the same way as an empty array? + +Gotcha covered. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + config.define_implicit_conversions +end + +null = NullObject.new + +null.to_str # => "" +null.to_ary # => [] + +a, b, c = [] +a # => nil +b # => nil +c # => nil +x, y, z = null +x # => nil +y # => nil +z # => nil +``` + +#### How about a null object that only stubs out the methods from a specific class? + +That's what `mimic` is for. + +```ruby +require 'naught' + +NullIO = Naught.build do |config| + config.mimic IO +end + +null_io = NullIO.new + +null_io << "foo" # => nil +null_io.readline # => nil +null_io.foobar # => +# ~> -:11:in `
    ': undefined method `foobar' for +# :NullIO (NoMethodError) +``` + +There is also `impersonate` which takes `mimic` one step further. The +generated null class will be derived from the impersonated class. This +is handy when refitting legacy code that contains type checks. + +```ruby +require 'naught' + +NullIO = Naught.build do |config| + config.impersonate IO +end + +null_io = NullIO.new +IO === null_io # => true + +case null_io +when IO + puts "Yep, checks out!" + null_io << "some output" +else + raise "Hey, I expected an IO!" +end +# >> Yep, checks out! +``` + +#### What about predicate methods? You know, the ones that end with question marks? Shouldn't they return `false` instead of `nil`? + +Sure, if you'd like. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + config.predicates_return false +end + +null = NullObject.new +null.foo # => nil +null.bar? # => false +null.nil? # => false +``` + +#### Alright smartypants. What if I want to add my own methods? + +Not a problem, just define them in the `.build` block. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + config.define_explicit_conversions + config.predicates_return false + def to_path + "/dev/null" + end + + # You can override methods generated by Naught + def to_s + "NOTHING TO SEE HERE MOVE ALONG" + end + + def nil? + true + end +end + +null = NullObject.new +null.to_path # => "/dev/null" +null.to_s # => "NOTHING TO SEE HERE MOVE ALONG" +null.nil? # => true +``` + +#### Got anything else up your sleeve? + +Well, we can make the null class a singleton, since null objects +generally have no state. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + config.singleton +end + +null = NullObject.instance + +null.__id__ # => 17844080 +NullObject.instance.__id__ # => 17844080 +NullObject.new # => +# ~> -:11:in `
    ': private method `new' called for +# NullObject:Class (NoMethodError) +``` + +Speaking of null objects with state, we can also enable tracing. This is +handy for playing "where'd that null come from?!" Try doing *that* with +`nil`! + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + config.traceable +end + +null = NullObject.new # line 7 + +null.__file__ # => "example.rb" +null.__line__ # => 7 +``` + +We can even conditionally enable either singleton mode (for production) +or tracing (for development). Here's an example of using the `$DEBUG` +global variable (set with the `-d` option to ruby) to choose which one. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + if $DEBUG + config.traceable + else + config.singleton + end +end +``` + +The only caveat is that when swapping between singleton and +non-singleton implementations, you should be careful to always +instantiate your null objects with `NullObject.get`, not `.new` or +`.instance`. `.get` will work whether the class is implemented as a +singleton or not. + +```ruby +NullObject.get # => +``` + +#### And if I want to know legacy code better? + +Naught can make a null object behave as a pebble object. + +```ruby +require 'naught' + +NullObject = Naught.build do |config| + if $DEBUG + config.pebble + else + config.black_hole + end +end +``` + +Now you can pass the pebble object to your code and see which messages are sent to the pebble. + +```ruby +null = NullObject.new + +class MyConsumer < Struct.new(:producer) + def consume + producer.produce + end +end + +MyConsumer.new(null).consume +# >> produce() from consume +# => +``` + +#### Are you done yet? + +Just one more thing. For maximum convenience, Naught-generated null +classes also come with a full suite of conversion functions which can be +included into your classes. + +```ruby +require 'naught' + +NullObject = Naught.build + +include NullObject::Conversions + +# Convert nil to null objects. Everything else passes through. +Maybe(42) # => 42 +Maybe(nil) # => +Maybe(NullObject.get) # => +Maybe{ 42 } # => 42 + +# Insist on a non-null (or nil) value +Just(42) # => 42 +Just(nil) rescue $! # => # +Just(NullObject.get) rescue $! # => #> + +# nils and nulls become nulls. Everything else is rejected. +Null() # => +Null(42) rescue $! # => # +Null(nil) # => +Null(NullObject.get) # => + +# Convert nulls back to nils. Everything else passes through. Useful +# for preventing null objects from "leaking" into public API return +# values. +Actual(42) # => 42 +Actual(nil) # => nil +Actual(NullObject.get) # => nil +Actual { 42 } # => 42 +``` + +Installation +-------------- + +``` {.example} +gem install naught +``` + +Requirements +-------------- + +- Ruby 1.9 + +Contributing +-------------- + +- Fork, branch, submit PR, blah blah blah. Don't forget tests. + +Who's responsible +------------------- + +Naught is by [Avdi Grimm](http://devblog.avdi.org/). + +Prior Art +--------- + +This isn't the first Ruby Null Object library. Others to check out include: + + - [NullAndVoid](https://github.com/jfelchner/null_and_void) + - [BlankSlate](https://github.com/saturnflyer/blank_slate) + + +Further reading +----------------- + +- [Null Object: Something for + Nothing](http://www.two-sdg.demon.co.uk/curbralan/papers/europlop/NullObject.pdf) + (PDF) by Kevlin Henney +- [The Null Object + Pattern](http://www.cs.oberlin.edu/~jwalker/refs/woolf.ps) (PS) by + Bobby Woolf +- [NullObject](http://www.c2.com/cgi/wiki?NullObject) on WikiWiki +- [Null Object + pattern](http://en.wikipedia.org/wiki/Null_Object_pattern) on + Wikipedia +- [Null Objects and + Falsiness](http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/), + by Avdi Grimm diff --git a/.gems/gems/naught-1.0.0/Rakefile b/.gems/gems/naught-1.0.0/Rakefile new file mode 100644 index 0000000..8d0de35 --- /dev/null +++ b/.gems/gems/naught-1.0.0/Rakefile @@ -0,0 +1,15 @@ +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +begin + require 'rubocop/rake_task' + Rubocop::RakeTask.new +rescue LoadError + task :rubocop do + $stderr.puts 'Rubocop is disabled' + end +end + +task :default => [:spec, :rubocop] diff --git a/.gems/gems/naught-1.0.0/lib/naught.rb b/.gems/gems/naught-1.0.0/lib/naught.rb new file mode 100644 index 0000000..27ec154 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught.rb @@ -0,0 +1,13 @@ +require 'naught/version' +require 'naught/null_class_builder' +require 'naught/null_class_builder/commands' + +module Naught + def self.build(&customization_block) + builder = NullClassBuilder.new + builder.customize(&customization_block) + builder.generate_class + end + module NullObjectTag + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/basic_object.rb b/.gems/gems/naught-1.0.0/lib/naught/basic_object.rb new file mode 100644 index 0000000..fc0c0ac --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/basic_object.rb @@ -0,0 +1,17 @@ +module Naught + if defined? ::BasicObject + class BasicObject < ::BasicObject + end + else + class BasicObject #:nodoc: + keep = %w[ + ! != == __id__ __send__ equal? instance_eval instance_exec + method_missing singleton_method_added singleton_method_removed + singleton_method_undefined + ] + instance_methods.each do |method_name| + undef_method(method_name) unless keep.include?(method_name) + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/conversions.rb b/.gems/gems/naught-1.0.0/lib/naught/conversions.rb new file mode 100644 index 0000000..a90e7db --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/conversions.rb @@ -0,0 +1,55 @@ +module Naught + module Conversions + def self.included(null_class) + unless class_variable_defined?(:@@included) && @@included + @@null_class = null_class + @@null_equivs = null_class::NULL_EQUIVS + @@included = true + end + super + end + + def Null(object = :nothing_passed) + case object + when NullObjectTag + object + when :nothing_passed, *@@null_equivs + @@null_class.get(:caller => caller(1)) + else + fail ArgumentError, "#{object.inspect} is not null!" + end + end + + def Maybe(object = nil) + object = yield if block_given? + case object + when NullObjectTag + object + when *@@null_equivs + @@null_class.get(:caller => caller(1)) + else + object + end + end + + def Just(object = nil) + object = yield if block_given? + case object + when NullObjectTag, *@@null_equivs + fail ArgumentError, "Null value: #{object.inspect}" + else + object + end + end + + def Actual(object = nil) + object = yield if block_given? + case object + when NullObjectTag + nil + else + object + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder.rb new file mode 100644 index 0000000..a137d09 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder.rb @@ -0,0 +1,186 @@ +require 'naught/basic_object' +require 'naught/conversions' + +module Naught + class NullClassBuilder + # make sure this module exists + module Commands + end + + attr_accessor :base_class, :inspect_proc, :interface_defined + + def initialize + @interface_defined = false + @base_class = Naught::BasicObject + @inspect_proc = lambda { '' } + @stub_strategy = :stub_method_returning_nil + define_basic_methods + end + + def interface_defined? + !!@interface_defined + end + + def customize(&customization_block) + return unless customization_block + customization_module.module_exec(self, &customization_block) + end + + def customization_module + @customization_module ||= Module.new + end + + def null_equivalents + @null_equivalents ||= [nil] + end + + def generate_class + respond_to_any_message unless interface_defined? + generation_mod = Module.new + customization_mod = customization_module # get a local binding + builder = self + + apply_operations(operations, generation_mod) + + null_class = Class.new(@base_class) do + const_set :GeneratedMethods, generation_mod + const_set :Customizations, customization_mod + const_set :NULL_EQUIVS, builder.null_equivalents + include Conversions + remove_const :NULL_EQUIVS + Conversions.instance_methods.each do |instance_method| + undef_method(instance_method) + end + const_set :Conversions, Conversions + + include NullObjectTag + include generation_mod + include customization_mod + end + + apply_operations(class_operations, null_class) + + null_class + end + + def method_missing(method_name, *args, &block) + command_name = command_name_for_method(method_name) + if Commands.const_defined?(command_name) + command_class = Commands.const_get(command_name) + command_class.new(self, *args, &block).call + else + super + end + end + + if RUBY_VERSION >= '1.9' + def respond_to_missing?(method_name, include_private = false) + command_name = command_name_for_method(method_name) + Commands.const_defined?(command_name) || super + rescue NameError + super + end + else + def respond_to?(method_name, include_private = false) + command_name = command_name_for_method(method_name) + Commands.const_defined?(command_name) || super + rescue NameError + super + end + end + + ############################################################################ + # Builder API + # + # See also the contents of lib/naught/null_class_builder/commands + ############################################################################ + + def black_hole + @stub_strategy = :stub_method_returning_self + end + + def respond_to_any_message + defer(:prepend => true) do |subject| + subject.module_eval do + def respond_to?(*) + true + end + end + stub_method(subject, :method_missing) + end + @interface_defined = true + end + + def defer(options = {}, &deferred_operation) + list = options[:class] ? class_operations : operations + if options[:prepend] + list.unshift(deferred_operation) + else + list << deferred_operation + end + end + + def stub_method(subject, name) + send(@stub_strategy, subject, name) + end + + private + + def define_basic_methods + define_basic_instance_methods + define_basic_class_methods + end + + def apply_operations(operations, module_or_class) + operations.each do |operation| + operation.call(module_or_class) + end + end + + def define_basic_instance_methods + defer do |subject| + subject.module_exec(@inspect_proc) do |inspect_proc| + define_method(:inspect, &inspect_proc) + def initialize(*) + end + end + end + end + + def define_basic_class_methods + defer(:class => true) do |subject| + subject.module_eval do + class << self + alias_method :get, :new + end + klass = self + define_method(:class) { klass } + end + end + end + + def class_operations + @class_operations ||= [] + end + + def operations + @operations ||= [] + end + + def stub_method_returning_nil(subject, name) + subject.module_eval do + define_method(name) { |*| nil } + end + end + + def stub_method_returning_self(subject, name) + subject.module_eval do + define_method(name) { |*| self } + end + end + + def command_name_for_method(method_name) + method_name.to_s.gsub(/(?:^|_)([a-z])/) { Regexp.last_match[1].upcase } + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/command.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/command.rb new file mode 100644 index 0000000..72b3b22 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/command.rb @@ -0,0 +1,20 @@ +module Naught + class NullClassBuilder + class Command + attr_reader :builder + + def initialize(builder) + @builder = builder + end + + def call + fail NotImplementedError, + 'Method #call should be overriden in child classes' + end + + def defer(options = {}, &block) + @builder.defer(options, &block) + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands.rb new file mode 100644 index 0000000..e26eb36 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands.rb @@ -0,0 +1,8 @@ +require 'naught/null_class_builder/commands/define_explicit_conversions' +require 'naught/null_class_builder/commands/define_implicit_conversions' +require 'naught/null_class_builder/commands/pebble' +require 'naught/null_class_builder/commands/predicates_return' +require 'naught/null_class_builder/commands/singleton' +require 'naught/null_class_builder/commands/traceable' +require 'naught/null_class_builder/commands/mimic' +require 'naught/null_class_builder/commands/impersonate' diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_explicit_conversions.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_explicit_conversions.rb new file mode 100644 index 0000000..7a45557 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_explicit_conversions.rb @@ -0,0 +1,15 @@ +require 'forwardable' +require 'naught/null_class_builder/command' + +module Naught::NullClassBuilder::Commands + class DefineExplicitConversions < ::Naught::NullClassBuilder::Command + def call + defer do |subject| + subject.module_eval do + extend Forwardable + def_delegators :nil, :to_a, :to_c, :to_f, :to_h, :to_i, :to_r, :to_s + end + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_implicit_conversions.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_implicit_conversions.rb new file mode 100644 index 0000000..8d352e2 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/define_implicit_conversions.rb @@ -0,0 +1,19 @@ +require 'naught/null_class_builder/command' + +module Naught::NullClassBuilder::Commands + class DefineImplicitConversions < ::Naught::NullClassBuilder::Command + def call + defer do |subject| + subject.module_eval do + def to_ary + [] + end + + def to_str + '' + end + end + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/impersonate.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/impersonate.rb new file mode 100644 index 0000000..11c3840 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/impersonate.rb @@ -0,0 +1,8 @@ +module Naught::NullClassBuilder::Commands + class Impersonate < Naught::NullClassBuilder::Commands::Mimic + def initialize(builder, class_to_impersonate, options = {}) + super + builder.base_class = class_to_impersonate + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/mimic.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/mimic.rb new file mode 100644 index 0000000..1156ebd --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/mimic.rb @@ -0,0 +1,37 @@ +require 'naught/basic_object' +require 'naught/null_class_builder/command' + +module Naught::NullClassBuilder::Commands + class Mimic < Naught::NullClassBuilder::Command + attr_reader :class_to_mimic, :include_super + + def initialize(builder, class_to_mimic, options = {}) + super(builder) + + @class_to_mimic = class_to_mimic + @include_super = options.fetch(:include_super) { true } + + builder.base_class = root_class_of(class_to_mimic) + builder.inspect_proc = lambda { "" } + builder.interface_defined = true + end + + def call + defer do |subject| + methods_to_stub.each do |method_name| + builder.stub_method(subject, method_name) + end + end + end + + private + + def root_class_of(klass) + klass.ancestors.include?(Object) ? Object : Naught::BasicObject + end + + def methods_to_stub + class_to_mimic.instance_methods(include_super) - Object.instance_methods + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/pebble.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/pebble.rb new file mode 100644 index 0000000..c6eb8ff --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/pebble.rb @@ -0,0 +1,34 @@ +require 'naught/null_class_builder/command' + +module Naught + class NullClassBuilder + module Commands + class Pebble < ::Naught::NullClassBuilder::Command + def initialize(builder, output = $stdout) + @builder = builder + @output = output + end + + def call + defer do |subject| + subject.module_exec(@output) do |output| + + define_method(:method_missing) do |method_name, *args, &block| + pretty_args = args.collect(&:inspect).join(', ').gsub("\"", "'") + output.puts "#{method_name}(#{pretty_args}) from #{parse_caller}" + self + end + + def parse_caller + caller = Kernel.caller(2).first + method_name = caller.match(/\`([\w\s]+(\(\d+\s\w+\))?[\w\s]*)/) + method_name ? method_name[1] : caller + end + private :parse_caller + end + end + end + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/predicates_return.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/predicates_return.rb new file mode 100644 index 0000000..6952e58 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/predicates_return.rb @@ -0,0 +1,46 @@ +require 'naught/null_class_builder/command' + +module Naught::NullClassBuilder::Commands + class PredicatesReturn < Naught::NullClassBuilder::Command + def initialize(builder, return_value) + super(builder) + @predicate_return_value = return_value + end + + def call + defer do |subject| + define_method_missing(subject) + define_predicate_methods(subject) + end + end + + private + + def define_method_missing(subject) + subject.module_exec(@predicate_return_value) do |return_value| + if subject.method_defined?(:method_missing) + original_method_missing = instance_method(:method_missing) + define_method(:method_missing) do |method_name, *args, &block| + if method_name.to_s.end_with?('?') + return_value + else + original_method_missing.bind(self).call(method_name, *args, &block) + end + end + end + end + end + + def define_predicate_methods(subject) + subject.module_exec(@predicate_return_value) do |return_value| + instance_methods.each do |method_name| + if method_name.to_s.end_with?('?') + define_method(method_name) do |*| + return_value + end + end + end + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/singleton.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/singleton.rb new file mode 100644 index 0000000..44a1b5b --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/singleton.rb @@ -0,0 +1,24 @@ +require 'naught/null_class_builder/command' + +module Naught::NullClassBuilder::Commands + class Singleton < Naught::NullClassBuilder::Command + def call + defer(:class => true) do |subject| + require 'singleton' + subject.module_eval do + include ::Singleton + + def self.get(*) + instance + end + + %w(dup clone).each do |method_name| + define_method method_name do + self + end + end + end + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/traceable.rb b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/traceable.rb new file mode 100644 index 0000000..93a7485 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/null_class_builder/commands/traceable.rb @@ -0,0 +1,20 @@ +require 'naught/null_class_builder/command' + +module Naught::NullClassBuilder::Commands + class Traceable < Naught::NullClassBuilder::Command + def call + defer do |subject| + subject.module_eval do + attr_reader :__file__, :__line__ + + def initialize(options = {}) + range = (RUBY_VERSION.to_f == 1.9 && RUBY_PLATFORM != 'java') ? 4 : 3 + backtrace = options.fetch(:caller) { Kernel.caller(range) } + @__file__, line, _ = backtrace[0].split(':') + @__line__ = line.to_i + end + end + end + end + end +end diff --git a/.gems/gems/naught-1.0.0/lib/naught/version.rb b/.gems/gems/naught-1.0.0/lib/naught/version.rb new file mode 100644 index 0000000..c2efe33 --- /dev/null +++ b/.gems/gems/naught-1.0.0/lib/naught/version.rb @@ -0,0 +1,3 @@ +module Naught + VERSION = '1.0.0' +end diff --git a/.gems/gems/naught-1.0.0/naught.gemspec b/.gems/gems/naught-1.0.0/naught.gemspec new file mode 100644 index 0000000..3a53542 --- /dev/null +++ b/.gems/gems/naught-1.0.0/naught.gemspec @@ -0,0 +1,22 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'naught/version' + +Gem::Specification.new do |spec| + spec.name = 'naught' + spec.version = Naught::VERSION + spec.authors = ['Avdi Grimm'] + spec.email = ['avdi@avdi.org'] + spec.description = %q{Naught is a toolkit for building Null Objects} + spec.summary = spec.description + spec.homepage = 'https://github.com/avdi/naught' + spec.license = 'MIT' + + spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR) + spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) } + spec.test_files = spec.files.grep(/^(test|spec|features)\//) + spec.require_paths = ['lib'] + + spec.add_development_dependency 'bundler', '~> 1.3' +end diff --git a/.gems/gems/naught-1.0.0/spec/base_object_spec.rb b/.gems/gems/naught-1.0.0/spec/base_object_spec.rb new file mode 100644 index 0000000..077a194 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/base_object_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe 'null object with a custom base class' do + + subject(:null) { custom_base_null_class.new } + + let(:custom_base_null_class) do + Naught.build do |b| + b.base_class = Object + end + end + + it 'respond to base class methods' do + expect(null.methods).to be_an Array + end + + it 'respond to unknown methods' do + expect(null.foo).to be_nil + end + + it 'exposes the default base class choice, for the curious' do + default_base_class = :not_set + Naught.build do |b| + default_base_class = b.base_class + end + expect(default_base_class).to eq(Naught::BasicObject) + end + + describe 'singleton null object' do + subject(:null_instance) { custom_base_singleton_null_class.instance } + + let(:custom_base_singleton_null_class) do + Naught.build do |b| + b.singleton + b.base_class = Object + end + end + + it 'can be cloned' do + expect(null_instance.clone).to be(null_instance) + end + + it 'can be duplicated' do + expect(null_instance.dup).to be(null_instance) + end + end +end diff --git a/.gems/gems/naught-1.0.0/spec/basic_null_object_spec.rb b/.gems/gems/naught-1.0.0/spec/basic_null_object_spec.rb new file mode 100644 index 0000000..8674831 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/basic_null_object_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'basic null object' do + let(:null_class) { Naught.build } + subject(:null) { null_class.new } + + it 'responds to arbitrary messages and returns nil' do + expect(null.info).to be_nil + expect(null.foobaz).to be_nil + expect(null.to_s).to be_nil + end + + it 'accepts any arguments for any messages' do + null.foobaz(1, 2, 3) + end + + it 'reports that it responds to any message' do + expect(null).to respond_to(:info) + expect(null).to respond_to(:foobaz) + expect(null).to respond_to(:to_s) + end + + it 'can be inspected' do + expect(null.inspect).to eq('') + end + + it 'knows its own class' do + expect(null.class).to eq(null_class) + end + + it 'aliases .new to .get' do + expect(null_class.get.class).to be(null_class) + end + +end diff --git a/.gems/gems/naught-1.0.0/spec/blackhole_spec.rb b/.gems/gems/naught-1.0.0/spec/blackhole_spec.rb new file mode 100644 index 0000000..79d84f2 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/blackhole_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe 'black hole null object' do + subject(:null) { null_class.new } + let(:null_class) do + Naught.build do |b| + b.black_hole + end + end + + it 'returns self from arbitray method calls' do + expect(null.info).to be(null) + expect(null.foobaz).to be(null) + expect(null << 'bar').to be(null) + end +end diff --git a/.gems/gems/naught-1.0.0/spec/explicit_conversions_spec.rb b/.gems/gems/naught-1.0.0/spec/explicit_conversions_spec.rb new file mode 100644 index 0000000..4a6d387 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/explicit_conversions_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper.rb' + +describe 'explicitly convertable null object' do + let(:null_class) do + Naught.build do |b| + b.define_explicit_conversions + end + end + subject(:null) { null_class.new } + + it 'defines common explicit conversions to return zero values' do + expect(null.to_s).to eq('') + expect(null.to_a).to eq([]) + expect(null.to_i).to eq(0) + expect(null.to_f).to eq(0.0) + if RUBY_VERSION >= '2.0' + expect(null.to_h).to eq({}) + elsif RUBY_VERSION >= '1.9' + expect(null.to_c).to eq(Complex(0)) + expect(null.to_r).to eq(Rational(0)) + end + end +end diff --git a/.gems/gems/naught-1.0.0/spec/functions/actual_spec.rb b/.gems/gems/naught-1.0.0/spec/functions/actual_spec.rb new file mode 100644 index 0000000..72e5033 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/functions/actual_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'Actual()' do + include ConvertableNull::Conversions + + specify 'given a null object, returns nil' do + null = ConvertableNull.get + expect(Actual(null)).to be_nil + end + + specify 'given anything else, returns the input unchanged' do + expect(Actual(false)).to be(false) + str = 'hello' + expect(Actual(str)).to be(str) + expect(Actual(nil)).to be_nil + end + + it 'also works with blocks' do + expect(Actual { ConvertableNull.new }).to be_nil + expect(Actual { 'foo' }).to eq('foo') + end +end diff --git a/.gems/gems/naught-1.0.0/spec/functions/just_spec.rb b/.gems/gems/naught-1.0.0/spec/functions/just_spec.rb new file mode 100644 index 0000000..9863817 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/functions/just_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'Just()' do + include ConvertableNull::Conversions + + specify 'passes non-nullish values through' do + expect(Just(false)).to be(false) + str = 'hello' + expect(Just(str)).to be(str) + end + + specify 'rejects nullish values' do + expect { Just(nil) }.to raise_error(ArgumentError) + expect { Just('') }.to raise_error(ArgumentError) + expect { Just(ConvertableNull.get) }.to raise_error(ArgumentError) + end + + it 'also works with blocks' do + expect { Just { nil }.class }.to raise_error(ArgumentError) + expect(Just { 'foo' }).to eq('foo') + end +end diff --git a/.gems/gems/naught-1.0.0/spec/functions/maybe_spec.rb b/.gems/gems/naught-1.0.0/spec/functions/maybe_spec.rb new file mode 100644 index 0000000..ae918d2 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/functions/maybe_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'Maybe()' do + include ConvertableNull::Conversions + + specify 'given nil, returns a null object' do + expect(Maybe(nil).class).to be(ConvertableNull) + end + + specify 'given a null object, returns the same null object' do + null = ConvertableNull.get + expect(Maybe(null)).to be(null) + end + + specify 'given anything in null_equivalents, return a null object' do + expect(Maybe('').class).to be(ConvertableNull) + end + + specify 'given anything else, returns the input unchanged' do + expect(Maybe(false)).to be(false) + str = 'hello' + expect(Maybe(str)).to be(str) + end + + it 'generates null objects with useful trace info' do + null, line = Maybe(), __LINE__ + expect(null.__file__).to eq(__FILE__) + expect(null.__line__).to eq(line) + end + + it 'also works with blocks' do + expect(Maybe { nil }.class).to eq(ConvertableNull) + expect(Maybe { 'foo' }).to eq('foo') + end +end diff --git a/.gems/gems/naught-1.0.0/spec/functions/null_spec.rb b/.gems/gems/naught-1.0.0/spec/functions/null_spec.rb new file mode 100644 index 0000000..417e4d1 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/functions/null_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'Null()' do + include ConvertableNull::Conversions + + specify 'given no input, returns a null object' do + expect(Null().class).to be(ConvertableNull) + end + + specify 'given nil, returns a null object' do + expect(Null(nil).class).to be(ConvertableNull) + end + + specify 'given a null object, returns the same null object' do + null = ConvertableNull.get + expect(Null(null)).to be(null) + end + + specify 'given anything in null_equivalents, return a null object' do + expect(Null('').class).to be(ConvertableNull) + end + + specify 'given anything else, raises an ArgumentError' do + expect { Null(false) }.to raise_error(ArgumentError) + expect { Null('hello') }.to raise_error(ArgumentError) + end + + it 'generates null objects with useful trace info' do + null, line = Null(), __LINE__ + expect(null.__file__).to eq(__FILE__) + expect(null.__line__).to eq(line) + end + +end diff --git a/.gems/gems/naught-1.0.0/spec/implicit_conversions_spec.rb b/.gems/gems/naught-1.0.0/spec/implicit_conversions_spec.rb new file mode 100644 index 0000000..88d4fb2 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/implicit_conversions_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe 'implicitly convertable null object' do + subject(:null) { null_class.new } + let(:null_class) do + Naught.build do |b| + b.define_implicit_conversions + end + end + it 'implicitly splats the same way an empty array does' do + a, b = null + expect(a).to be_nil + expect(b).to be_nil + end + it 'is implicitly convertable to String' do + expect(instance_eval(null)).to be_nil + end + it 'implicitly converts to an empty array' do + expect(null.to_ary).to eq([]) + end + it 'implicitly converts to an empty string' do + expect(null.to_str).to eq('') + end + +end diff --git a/.gems/gems/naught-1.0.0/spec/mimic_spec.rb b/.gems/gems/naught-1.0.0/spec/mimic_spec.rb new file mode 100644 index 0000000..4a17fbf --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/mimic_spec.rb @@ -0,0 +1,117 @@ +require 'spec_helper' +require 'logger' + +describe 'null object mimicking a class' do + class User + def login + 'bob' + end + end + + module Authorizable + def authorized_for?(object) + true + end + end + + class LibraryPatron < User + include Authorizable + + def member? + true + end + + def name + 'Bob' + end + + def notify_of_overdue_books(titles) + puts 'Notifying...' + end + end + + subject(:null) { mimic_class.new } + let(:mimic_class) do + Naught.build do |b| + b.mimic LibraryPatron + end + end + it 'responds to all methods defined on the target class' do + expect(null.member?).to be_nil + expect(null.name).to be_nil + expect(null.notify_of_overdue_books(['The Grapes of Wrath'])).to be_nil + end + + it 'does not respond to methods not defined on the target class' do + expect { null.foobar }.to raise_error(NoMethodError) + end + + it 'reports which messages it does and does not respond to' do + expect(null).to respond_to(:member?) + expect(null).to respond_to(:name) + expect(null).to respond_to(:notify_of_overdue_books) + expect(null).not_to respond_to(:foobar) + end + it 'has an informative inspect string' do + expect(null.inspect).to eq('') + end + + it 'excludes Object methods from being mimicked' do + expect(null.object_id).not_to be_nil + expect(null.hash).not_to be_nil + end + + it 'includes inherited methods' do + expect(null.authorized_for?('something')).to be_nil + expect(null.login).to be_nil + end + + describe 'with include_super: false' do + let(:mimic_class) do + Naught.build do |b| + b.mimic LibraryPatron, :include_super => false + end + end + + it 'excludes inherited methods' do + expect(null).to_not respond_to(:authorized_for?) + expect(null).to_not respond_to(:login) + end + end +end + +describe 'using mimic with black_hole' do + subject(:null) { mimic_class.new } + let(:mimic_class) do + Naught.build do |b| + b.mimic Logger + b.black_hole + end + end + + def self.it_behaves_like_a_black_hole_mimic + it 'returns self from mimicked methods' do + expect(null.info).to equal(null) + expect(null.error).to equal(null) + expect(null << 'test').to equal(null) + end + + it 'does not respond to methods not defined on the target class' do + expect { null.foobar }.to raise_error(NoMethodError) + end + end + + it_behaves_like_a_black_hole_mimic + + describe '(reverse order)' do + let(:mimic_class) do + Naught.build do |b| + b.black_hole + b.mimic Logger + end + end + + it_behaves_like_a_black_hole_mimic + end + +end diff --git a/.gems/gems/naught-1.0.0/spec/naught/null_object_builder/command_spec.rb b/.gems/gems/naught-1.0.0/spec/naught/null_object_builder/command_spec.rb new file mode 100644 index 0000000..0cd749a --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/naught/null_object_builder/command_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' + +module Naught + describe NullClassBuilder::Command do + it 'is abstract' do + command = NullClassBuilder::Command.new(nil) + expect { command.call }.to raise_error(NotImplementedError) + end + end +end diff --git a/.gems/gems/naught-1.0.0/spec/naught/null_object_builder_spec.rb b/.gems/gems/naught-1.0.0/spec/naught/null_object_builder_spec.rb new file mode 100644 index 0000000..d639aff --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/naught/null_object_builder_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +module Naught + class NullClassBuilder + module Commands + class TestCommand + end + end + end + + describe NullClassBuilder do + subject(:builder) { NullClassBuilder.new } + it 'responds to commands defined in NullObjectBuilder::Commands' do + expect(builder).to respond_to(:test_command) + end + + it 'translates method calls into command invocations including arguments' do + test_command = double + expect(NullClassBuilder::Commands::TestCommand).to receive(:new). + with(builder, 'foo', 42). + and_return(test_command) + expect(test_command).to receive(:call).and_return('COMMAND RESULT') + expect(builder.test_command('foo', 42)).to eq('COMMAND RESULT') + end + + it 'handles missing non-command missing methods normally' do + expect(builder).not_to respond_to(:nonexistant_method) + expect { builder.nonexistent_method }.to raise_error(NoMethodError) + end + end +end diff --git a/.gems/gems/naught-1.0.0/spec/naught_spec.rb b/.gems/gems/naught-1.0.0/spec/naught_spec.rb new file mode 100644 index 0000000..caafd04 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/naught_spec.rb @@ -0,0 +1,101 @@ +require 'spec_helper' + +describe 'null object impersonating another type' do + class Point + def x + 23 + end + + def y + 42 + end + end + + subject(:null) { impersonation_class.new } + let(:impersonation_class) do + Naught.build do |b| + b.impersonate Point + end + end + + it 'matches the impersonated type' do + expect(null).to be_a Point + end + + it 'responds to methods from the impersonated type' do + expect(null.x).to be_nil + expect(null.y).to be_nil + end + + it 'does not respond to unknown methods' do + expect { null.foo }.to raise_error(NoMethodError) + end +end + +describe 'traceable null object' do + subject(:trace_null) do + null_object_and_line.first + end + let(:null_object_and_line) do + obj, line = trace_null_class.new, __LINE__ + [obj, line] + end + let(:instantiation_line) { null_object_and_line.last } + let(:trace_null_class) do + Naught.build do |b| + b.traceable + end + end + + it 'remembers the file it was instantiated from' do + expect(trace_null.__file__).to eq(__FILE__) + end + + it 'remembers the line it was instantiated from' do + expect(trace_null.__line__).to eq(instantiation_line) + end + + def make_null + trace_null_class.get(:caller => caller(1)) + end + + it 'can accept custom backtrace info' do + obj, line = make_null, __LINE__ + expect(obj.__line__).to eq(line) + end +end + +describe 'customized null object' do + subject(:custom_null) { custom_null_class.new } + let(:custom_null_class) do + Naught.build do |b| + b.define_explicit_conversions + def to_path + '/dev/null' + end + + def to_s + 'NOTHING TO SEE HERE' + end + end + end + + it 'responds to custom-defined methods' do + expect(custom_null.to_path).to eq('/dev/null') + end + + it 'allows generated methods to be overridden' do + expect(custom_null.to_s).to eq('NOTHING TO SEE HERE') + end +end +TestNull = Naught.build + +describe 'a named null object class' do + it 'has named ancestor modules', :pending => rubinius? do + expect(TestNull.ancestors[0..2].collect(&:name)).to eq([ + 'TestNull', + 'TestNull::Customizations', + 'TestNull::GeneratedMethods' + ]) + end +end diff --git a/.gems/gems/naught-1.0.0/spec/pebble_spec.rb b/.gems/gems/naught-1.0.0/spec/pebble_spec.rb new file mode 100644 index 0000000..caba3ca --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/pebble_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' +require 'stringio' + +describe 'pebble null object' do + class Caller + def call_method(thing) + thing.info + end + + def call_method_inside_block(thing) + 2.times.each { thing.info } + end + + def call_method_inside_nested_block(thing) + 2.times.each { 2.times.each { thing.info } } + end + end + + subject(:null) { null_class.new } + let(:null_class) do + output = test_output # getting local binding + Naught.build do |b| + b.pebble output + end + end + + let(:test_output) { StringIO.new } + + it 'prints the name of the method called' do + expect(test_output).to receive(:puts).with(/^info\(\)/) + null.info + end + + it 'prints the arguments received' do + expect(test_output).to receive(:puts).with(/^info\(\'foo\', 5, \:sym\)/) + null.info('foo', 5, :sym) + end + + it 'prints the name of the caller' do + expect(test_output).to receive(:puts).with(/from call_method$/) + Caller.new.call_method(null) + end + + it 'returns self' do + expect(null.info).to be(null) + end + + context 'when is called from a block' do + it 'prints the indication of a block', + :pending => jruby? || rubinius? || ruby_18? do + expect(test_output).to receive(:puts).twice. + with(/from block/) + Caller.new.call_method_inside_block(null) + end + + it 'prints the name of the method that has the block' do + expect(test_output).to receive(:puts).twice. + with(/call_method_inside_block$/) + Caller.new.call_method_inside_block(null) + end + end + + context 'when is called from many levels blocks' do + it 'prints the indication of blocks and its levels', + :pending => jruby? || rubinius? || ruby_18? do + expect(test_output).to receive(:puts).exactly(4).times. + with(/from block \(2 levels\)/) + Caller.new.call_method_inside_nested_block(null) + end + + it 'prints the name of the method that has the block' do + expect(test_output).to receive(:puts).exactly(4).times. + with(/call_method_inside_nested_block$/) + Caller.new.call_method_inside_nested_block(null) + end + end +end diff --git a/.gems/gems/naught-1.0.0/spec/predicate_spec.rb b/.gems/gems/naught-1.0.0/spec/predicate_spec.rb new file mode 100644 index 0000000..132b36b --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/predicate_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' + +describe 'a null object with predicates_return(false)' do + subject(:null) { null_class.new } + let(:null_class) do + Naught.build do |config| + config.predicates_return false + end + end + + it 'responds to predicate-style methods with false' do + expect(null.too_much_coffee?).to eq(false) + end + + it 'responds to other methods with nil' do + expect(null.foobar).to eq(nil) + end + + describe '(black hole)' do + let(:null_class) do + Naught.build do |config| + config.black_hole + config.predicates_return false + end + end + + it 'responds to predicate-style methods with false' do + expect(null.too_much_coffee?).to eq(false) + end + + it 'responds to other methods with self' do + expect(null.foobar).to be(null) + end + end + + describe '(black hole, reverse order config)' do + let(:null_class) do + Naught.build do |config| + config.predicates_return false + config.black_hole + end + end + + it 'responds to predicate-style methods with false' do + expect(null.too_much_coffee?).to eq(false) + end + + it 'responds to other methods with self' do + expect(null.foobar).to be(null) + end + end + + class Coffee + def black? + true + end + + def origin + 'Ethiopia' + end + end + + describe '(mimic)' do + let(:null_class) do + Naught.build do |config| + config.mimic Coffee + config.predicates_return false + end + end + + it 'responds to predicate-style methods with false' do + expect(null.black?).to eq(false) + end + + it 'responds to other methods with nil' do + expect(null.origin).to be(nil) + end + + it 'does not respond to undefined methods' do + expect(null).not_to respond_to(:leaf_variety) + expect { null.leaf_variety }.to raise_error(NoMethodError) + end + end +end diff --git a/.gems/gems/naught-1.0.0/spec/singleton_null_object_spec.rb b/.gems/gems/naught-1.0.0/spec/singleton_null_object_spec.rb new file mode 100644 index 0000000..0cc9a3f --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/singleton_null_object_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'singleton null object' do + subject(:null_class) do + Naught.build do |b| + b.singleton + end + end + + it 'does not respond to .new' do + expect { null_class.new }.to raise_error + end + + it 'has only one instance' do + null1 = null_class.instance + null2 = null_class.instance + expect(null1).to be(null2) + end + + it 'can be cloned' do + null = null_class.instance + expect(null.clone).to be(null) + end + + it 'can be duplicated' do + null = null_class.instance + expect(null.dup).to be(null) + end + it 'aliases .instance to .get' do + expect(null_class.get).to be null_class.instance + end + it 'permits arbitrary arguments to be passed to .get' do + null_class.get(42, :foo => 'bar') + end +end diff --git a/.gems/gems/naught-1.0.0/spec/spec_helper.rb b/.gems/gems/naught-1.0.0/spec/spec_helper.rb new file mode 100644 index 0000000..e58b711 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/spec_helper.rb @@ -0,0 +1,13 @@ +GEM_ROOT = File.expand_path('../../', __FILE__) +$LOAD_PATH.unshift File.join(GEM_ROOT, 'lib') + +if ENV['TRAVIS'] + require 'coveralls' + Coveralls.wear! +else + require 'simplecov' + SimpleCov.start +end + +require 'naught' +Dir[File.join(GEM_ROOT, 'spec', 'support', '**/*.rb')].each { |f| require f } diff --git a/.gems/gems/naught-1.0.0/spec/support/convertable_null.rb b/.gems/gems/naught-1.0.0/spec/support/convertable_null.rb new file mode 100644 index 0000000..8b8d43b --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/support/convertable_null.rb @@ -0,0 +1,4 @@ +ConvertableNull = Naught.build do |b| + b.null_equivalents << '' + b.traceable +end diff --git a/.gems/gems/naught-1.0.0/spec/support/jruby.rb b/.gems/gems/naught-1.0.0/spec/support/jruby.rb new file mode 100644 index 0000000..5e6db75 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/support/jruby.rb @@ -0,0 +1,3 @@ +def jruby? + RUBY_PLATFORM == 'java' +end diff --git a/.gems/gems/naught-1.0.0/spec/support/rubinius.rb b/.gems/gems/naught-1.0.0/spec/support/rubinius.rb new file mode 100644 index 0000000..949586f --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/support/rubinius.rb @@ -0,0 +1,3 @@ +def rubinius? + defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' +end diff --git a/.gems/gems/naught-1.0.0/spec/support/ruby_18.rb b/.gems/gems/naught-1.0.0/spec/support/ruby_18.rb new file mode 100644 index 0000000..ba9eae7 --- /dev/null +++ b/.gems/gems/naught-1.0.0/spec/support/ruby_18.rb @@ -0,0 +1,3 @@ +def ruby_18? + RUBY_VERSION.to_f == 1.8 +end diff --git a/.gems/gems/simple_oauth-0.2.0/.gemtest b/.gems/gems/simple_oauth-0.2.0/.gemtest new file mode 100644 index 0000000..e69de29 diff --git a/.gems/gems/simple_oauth-0.2.0/.gitignore b/.gems/gems/simple_oauth-0.2.0/.gitignore new file mode 100644 index 0000000..74d8b53 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/.gitignore @@ -0,0 +1,9 @@ +*.rbc +.bundle +.DS_Store +.yardoc +coverage +doc +Gemfile.lock +pkg +rdoc diff --git a/.gems/gems/simple_oauth-0.2.0/.rspec b/.gems/gems/simple_oauth-0.2.0/.rspec new file mode 100644 index 0000000..0ea59b0 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/.rspec @@ -0,0 +1,3 @@ +--color +--fail-fast +--order random diff --git a/.gems/gems/simple_oauth-0.2.0/.travis.yml b/.gems/gems/simple_oauth-0.2.0/.travis.yml new file mode 100644 index 0000000..0828e27 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/.travis.yml @@ -0,0 +1,10 @@ +language: ruby +rvm: + - rbx-18mode + - rbx-19mode + - jruby-18mode + - jruby-19mode + - 1.8.7 + - 1.9.2 + - 1.9.3 + - ruby-head diff --git a/.gems/gems/simple_oauth-0.2.0/.yardopts b/.gems/gems/simple_oauth-0.2.0/.yardopts new file mode 100644 index 0000000..70bb7f2 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/.yardopts @@ -0,0 +1,4 @@ +--markup markdown +- +HISTORY.md +LICENSE.md diff --git a/.gems/gems/simple_oauth-0.2.0/CONTRIBUTING.md b/.gems/gems/simple_oauth-0.2.0/CONTRIBUTING.md new file mode 100644 index 0000000..c556c97 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/CONTRIBUTING.md @@ -0,0 +1,8 @@ +## Contributing +1. Fork the project. +2. Create a topic branch. +3. Add failing tests. +4. Add code to pass the failing tests. +5. Run `bundle exec rake`. If failing, repeat step 4. +6. Commit and push your changes. +7. Submit a pull request. Please do not include changes to the gemspec. diff --git a/.gems/gems/simple_oauth-0.2.0/Gemfile b/.gems/gems/simple_oauth-0.2.0/Gemfile new file mode 100644 index 0000000..f50abda --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +platforms :jruby do + gem 'jruby-openssl', '~> 0.7' +end + +gemspec diff --git a/.gems/gems/simple_oauth-0.2.0/LICENSE b/.gems/gems/simple_oauth-0.2.0/LICENSE new file mode 100644 index 0000000..24e2cf9 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2010 Steve Richert, Erik Michaels-Ober + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.gems/gems/simple_oauth-0.2.0/README.md b/.gems/gems/simple_oauth-0.2.0/README.md new file mode 100644 index 0000000..a532562 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/README.md @@ -0,0 +1,33 @@ +# simple_oauth [![Build Status](https://secure.travis-ci.org/laserlemon/simple_oauth.png)](http://travis-ci.org/laserlemon/simple_oauth) [![Dependency Status](https://gemnasium.com/laserlemon/simple_oauth.png)](https://gemnasium.com/laserlemon/simple_oauth) + +Simply builds and verifies OAuth headers + +## Supported Rubies +This library aims to support and is [tested +against](http://travis-ci.org/laserlemon/simple_oauth) the following Ruby +implementations: + +* Ruby 1.8.7 +* Ruby 1.9.2 +* Ruby 1.9.3 +* Ruby head +* [JRuby](http://www.jruby.org/) +* [Rubinius](http://rubini.us/) + +If something doesn't work on one of these interpreters, it should be considered +a bug. + +This library may inadvertently work (or seem to work) on other Ruby +implementations, however support will only be provided for the versions listed +above. + +If you would like this library to support another Ruby version, you may +volunteer to be a maintainer. Being a maintainer entails making sure all tests +run and pass on that implementation. When something breaks on your +implementation, you will be personally responsible for providing patches in a +timely fashion. If critical issues for a particular implementation exist at the +time of a major release, support for that Ruby version may be dropped. + +## Copyright +Copyright (c) 2010 Steve Richert, Erik Michaels-Ober. +See [LICENSE](https://github.com/laserlemon/simple_oauth/blob/master/LICENSE) for details. diff --git a/.gems/gems/simple_oauth-0.2.0/Rakefile b/.gems/gems/simple_oauth-0.2.0/Rakefile new file mode 100644 index 0000000..93cb943 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/Rakefile @@ -0,0 +1,6 @@ +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/.gems/gems/simple_oauth-0.2.0/lib/simple_oauth.rb b/.gems/gems/simple_oauth-0.2.0/lib/simple_oauth.rb new file mode 100644 index 0000000..f2bc580 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/lib/simple_oauth.rb @@ -0,0 +1 @@ +require 'simple_oauth/header' diff --git a/.gems/gems/simple_oauth-0.2.0/lib/simple_oauth/header.rb b/.gems/gems/simple_oauth-0.2.0/lib/simple_oauth/header.rb new file mode 100644 index 0000000..16aa6e4 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/lib/simple_oauth/header.rb @@ -0,0 +1,126 @@ +require 'openssl' +require 'uri' +require 'base64' +require 'cgi' + +module SimpleOAuth + class Header + ATTRIBUTE_KEYS = [:callback, :consumer_key, :nonce, :signature_method, :timestamp, :token, :verifier, :version] unless defined? ::SimpleOAuth::Header::ATTRIBUTE_KEYS + attr_reader :method, :params, :options + + class << self + def default_options + { + :nonce => OpenSSL::Random.random_bytes(16).unpack('H*')[0], + :signature_method => 'HMAC-SHA1', + :timestamp => Time.now.to_i.to_s, + :version => '1.0' + } + end + + def parse(header) + header.to_s.sub(/^OAuth\s/, '').split(/,\s*/).inject({}) do |attributes, pair| + match = pair.match(/^(\w+)\=\"([^\"]*)\"$/) + attributes.merge(match[1].sub(/^oauth_/, '').to_sym => decode(match[2])) + end + end + + def escape(value) + uri_parser.escape(value.to_s, /[^a-z0-9\-\.\_\~]/i) + end + alias encode escape + + def unescape(value) + uri_parser.unescape(value.to_s) + end + alias decode unescape + + private + + def uri_parser + @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI + end + + end + + def initialize(method, url, params, oauth = {}) + @method = method.to_s.upcase + @uri = URI.parse(url.to_s) + @uri.scheme = @uri.scheme.downcase + @uri.normalize! + @uri.fragment = nil + @params = params + @options = oauth.is_a?(Hash) ? self.class.default_options.merge(oauth) : self.class.parse(oauth) + end + + def url + uri = @uri.dup + uri.query = nil + uri.to_s + end + + def to_s + "OAuth #{normalized_attributes}" + end + + def valid?(secrets = {}) + original_options = options.dup + options.merge!(secrets) + valid = options[:signature] == signature + options.replace(original_options) + valid + end + + def signed_attributes + attributes.merge(:oauth_signature => signature) + end + + private + + def normalized_attributes + signed_attributes.sort_by{|k,v| k.to_s }.map{|k,v| %(#{k}="#{self.class.encode(v)}") }.join(', ') + end + + def attributes + ATTRIBUTE_KEYS.inject({}){|a,k| options[k] ? a.merge(:"oauth_#{k}" => options[k]) : a } + end + + def signature + send(options[:signature_method].downcase.tr('-', '_') + '_signature') + end + + def hmac_sha1_signature + Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, secret, signature_base)).chomp.gsub(/\n/, '') + end + + def secret + options.values_at(:consumer_secret, :token_secret).map{|v| self.class.encode(v) }.join('&') + end + alias_method :plaintext_signature, :secret + + def signature_base + [method, url, normalized_params].map{|v| self.class.encode(v) }.join('&') + end + + def normalized_params + signature_params.map{|p| p.map{|v| self.class.encode(v) } }.sort.map{|p| p.join('=') }.join('&') + end + + def signature_params + attributes.to_a + params.to_a + url_params + end + + def url_params + CGI.parse(@uri.query || '').inject([]){|p,(k,vs)| p + vs.sort.map{|v| [k, v] } } + end + + def rsa_sha1_signature + Base64.encode64(private_key.sign(OpenSSL::Digest::SHA1.new, signature_base)).chomp.gsub(/\n/, '') + end + + def private_key + OpenSSL::PKey::RSA.new(options[:consumer_secret]) + end + + end +end diff --git a/.gems/gems/simple_oauth-0.2.0/simple_oauth.gemspec b/.gems/gems/simple_oauth-0.2.0/simple_oauth.gemspec new file mode 100644 index 0000000..d99d926 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/simple_oauth.gemspec @@ -0,0 +1,21 @@ +# encoding: utf-8 + +Gem::Specification.new do |spec| + spec.name = 'simple_oauth' + spec.version = '0.2.0' + + spec.authors = ["Steve Richert", "Erik Michaels-Ober"] + spec.email = ['steve.richert@gmail.com', 'sferik@gmail.com'] + spec.description = 'Simply builds and verifies OAuth headers' + spec.summary = spec.description + spec.homepage = 'https://github.com/laserlemon/simple_oauth' + spec.licenses = ['MIT'] + + spec.add_development_dependency 'rake' + spec.add_development_dependency 'rspec', '>= 2' + spec.add_development_dependency 'simplecov' + + spec.files = `git ls-files`.split($\) + spec.test_files = spec.files.grep(/^test\//) + spec.require_paths = ["lib"] +end diff --git a/.gems/gems/simple_oauth-0.2.0/spec/helper.rb b/.gems/gems/simple_oauth-0.2.0/spec/helper.rb new file mode 100644 index 0000000..9be179d --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/spec/helper.rb @@ -0,0 +1,21 @@ +unless ENV['CI'] + require 'simplecov' + SimpleCov.start do + add_filter 'spec' + end +end + +require 'simple_oauth' +require 'rspec' + +def uri_parser + @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI +end + +RSpec.configure do |config| + config.expect_with :rspec do |c| + c.syntax = :expect + end +end + +Dir[File.expand_path('../support/**/*.rb', __FILE__)].each{|f| require f } diff --git a/.gems/gems/simple_oauth-0.2.0/spec/simple_oauth/header_spec.rb b/.gems/gems/simple_oauth-0.2.0/spec/simple_oauth/header_spec.rb new file mode 100644 index 0000000..466a6e3 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/spec/simple_oauth/header_spec.rb @@ -0,0 +1,372 @@ +# encoding: utf-8 + +require 'helper' + +describe SimpleOAuth::Header do + describe ".default_options" do + let(:default_options){ SimpleOAuth::Header.default_options } + + it "is different every time" do + expect(SimpleOAuth::Header.default_options).not_to eq default_options + end + + it "is used for new headers" do + SimpleOAuth::Header.stub(:default_options => default_options) + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) + expect(header.options).to eq default_options + end + + it "includes a signature method and an OAuth version" do + expect(default_options[:signature_method]).not_to be_nil + expect(default_options[:version]).not_to be_nil + end + end + + describe ".escape" do + it "escapes (most) non-word characters" do + [' ', '!', '@', '#', '$', '%', '^', '&'].each do |character| + escaped = SimpleOAuth::Header.escape(character) + expect(escaped).not_to eq character + expect(escaped).to eq uri_parser.escape(character, /.*/) + end + end + + it "does not escape - . or ~" do + ['-', '.', '~'].each do |character| + escaped = SimpleOAuth::Header.escape(character) + expect(escaped).to eq character + end + end + + def self.test_special_characters + it "escapes non-ASCII characters" do + expect(SimpleOAuth::Header.escape('é')).to eq '%C3%A9' + end + + it "escapes multibyte characters" do + expect(SimpleOAuth::Header.escape('あ')).to eq '%E3%81%82' + end + end + + if RUBY_VERSION >= '1.9' + test_special_characters + else + %w(n N e E s S u U).each do |kcode| + describe %(when $KCODE = "#{kcode}") do + original_kcode = $KCODE + begin + $KCODE = kcode + test_special_characters + ensure + $KCODE = original_kcode + end + end + end + end + end + + describe ".unescape" do + pending + end + + describe ".parse" do + let(:header){ SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}) } + let(:parsed_options){ SimpleOAuth::Header.parse(header) } + + it "returns a hash" do + expect(parsed_options).to be_a(Hash) + end + + it "includes the options used to build the header" do + expect(parsed_options.reject{|k,_| k == :signature }).to eq header.options + end + + it "includes a signature" do + expect(header.options).not_to have_key(:signature) + expect(parsed_options).to have_key(:signature) + expect(parsed_options[:signature]).not_to be_nil + end + + it "handles optional 'linear white space'" do + parsed_header_with_spaces = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + expect(parsed_header_with_spaces).to be_a_kind_of(Hash) + expect(parsed_header_with_spaces.keys.size).to eq 7 + + parsed_header_with_tabs = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + expect(parsed_header_with_tabs).to be_a_kind_of(Hash) + expect(parsed_header_with_tabs.keys.size).to eq 7 + + parsed_header_with_spaces_and_tabs = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + expect(parsed_header_with_spaces_and_tabs).to be_a_kind_of(Hash) + expect(parsed_header_with_spaces_and_tabs.keys.size).to eq 7 + + parsed_header_without_spaces = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd",oauth_nonce="oLKtec51GQy",oauth_signature="efgh%26mnop",oauth_signature_method="PLAINTEXT",oauth_timestamp="1286977095",oauth_token="ijkl",oauth_version="1.0"' + expect(parsed_header_without_spaces).to be_a_kind_of(Hash) + expect(parsed_header_without_spaces.keys.size).to eq 7 + end + end + + describe "#initialize" do + let(:header){ SimpleOAuth::Header.new(:get, 'HTTPS://api.TWITTER.com:443/1/statuses/friendships.json?foo=bar#anchor', {}) } + + it "stringifies and uppercases the request method" do + expect(header.method).to eq 'GET' + end + + it "downcases the scheme and authority" do + expect(header.url).to match %r(^https://api\.twitter\.com/) + end + + it "ignores the query and fragment" do + expect(header.url).to match %r(/1/statuses/friendships\.json$) + end + end + + describe "#valid?" do + context "using the HMAC-SHA1 signature method" do + it "requires consumer and token secrets" do + secrets = {:consumer_secret => 'CONSUMER_SECRET', :token_secret => 'TOKEN_SECRET'} + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, secrets) + parsed_header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, header) + expect(parsed_header).not_to be_valid + expect(parsed_header).to be_valid(secrets) + end + end + + context "using the RSA-SHA1 signature method" do + it "requires an identical private key" do + secrets = {:consumer_secret => rsa_private_key} + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, secrets.merge(:signature_method => 'RSA-SHA1')) + parsed_header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, header) + expect{ parsed_header.valid? }.to raise_error(TypeError) + expect(parsed_header).to be_valid(secrets) + end + end + + context "using the RSA-SHA1 signature method" do + it "requires consumer and token secrets" do + secrets = {:consumer_secret => 'CONSUMER_SECRET', :token_secret => 'TOKEN_SECRET'} + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, secrets.merge(:signature_method => 'PLAINTEXT')) + parsed_header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, header) + expect(parsed_header).not_to be_valid + expect(parsed_header).to be_valid(secrets) + end + end + end + + describe "#normalized_attributes" do + let(:header){ SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}) } + let(:normalized_attributes){ header.send(:normalized_attributes) } + + it "returns a sorted-key, quoted-value and comma-separated list" do + header.stub(:signed_attributes => {:d => 1, :c => 2, :b => 3, :a => 4}) + expect(normalized_attributes).to eq 'a="4", b="3", c="2", d="1"' + end + + it "URI encodes its values" do + header.stub(:signed_attributes => {1 => '!', 2 => '@', 3 => '#', 4 => '$'}) + expect(normalized_attributes).to eq '1="%21", 2="%40", 3="%23", 4="%24"' + end + end + + describe "#signed_attributes" do + it "includes the OAuth signature" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}) + expect(header.send(:signed_attributes)).to have_key(:oauth_signature) + end + end + + describe "#attributes" do + let(:header) do + options = {} + SimpleOAuth::Header::ATTRIBUTE_KEYS.each{|k| options[k] = k.to_s.upcase } + options[:other] = 'OTHER' + SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}, options) + end + let(:attributes){ header.send(:attributes) } + + it "prepends keys with 'oauth_'" do + expect(attributes.keys).to be_all{|k| k.to_s =~ /^oauth_/ } + end + + it "excludes keys not included in the list of valid attributes" do + expect(attributes.keys).to be_all{|k| k.is_a?(Symbol) } + expect(attributes).not_to have_key(:oauth_other) + end + + it "preserves values for valid keys" do + expect(attributes.size).to eq SimpleOAuth::Header::ATTRIBUTE_KEYS.size + expect(attributes).to be_all{|k,v| k.to_s == "oauth_#{v.downcase}" } + end + end + + describe "#signature" do + context "calls the appropriate signature method" do + specify "when using HMAC-SHA1" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, :signature_method => 'HMAC-SHA1') + header.should_receive(:hmac_sha1_signature).once.and_return('HMAC_SHA1_SIGNATURE') + expect(header.send(:signature)).to eq 'HMAC_SHA1_SIGNATURE' + end + + specify "when using RSA-SHA1" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, :signature_method => 'RSA-SHA1') + header.should_receive(:rsa_sha1_signature).once.and_return('RSA_SHA1_SIGNATURE') + expect(header.send(:signature)).to eq 'RSA_SHA1_SIGNATURE' + end + + specify "when using PLAINTEXT" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, :signature_method => 'PLAINTEXT') + header.should_receive(:plaintext_signature).once.and_return('PLAINTEXT_SIGNATURE') + expect(header.send(:signature)).to eq 'PLAINTEXT_SIGNATURE' + end + end + end + + describe "#hmac_sha1_signature" do + it "reproduces a successful Twitter GET" do + options = { + :consumer_key => '8karQBlMg6gFOwcf8kcoYw', + :consumer_secret => '3d0vcHyUiiqADpWxolW8nlDIpSWMlyK7YNgc5Qna2M', + :nonce => '547fed103e122eecf84c080843eedfe6', + :signature_method => 'HMAC-SHA1', + :timestamp => '1286830180', + :token => '201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh', + :token_secret => 'T5qa1tF57tfDzKmpM89DHsNuhgOY4NT6DlNLsTFcuQ' + } + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, options) + expect(header.to_s).to eq 'OAuth oauth_consumer_key="8karQBlMg6gFOwcf8kcoYw", oauth_nonce="547fed103e122eecf84c080843eedfe6", oauth_signature="i9CT6ahDRAlfGX3hKYf78QzXsaw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1286830180", oauth_token="201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh", oauth_version="1.0"' + end + + it "reproduces a successful Twitter POST" do + options = { + :consumer_key => '8karQBlMg6gFOwcf8kcoYw', + :consumer_secret => '3d0vcHyUiiqADpWxolW8nlDIpSWMlyK7YNgc5Qna2M', + :nonce => 'b40a3e0f18590ecdcc0e273f7d7c82f8', + :signature_method => 'HMAC-SHA1', + :timestamp => '1286830181', + :token => '201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh', + :token_secret => 'T5qa1tF57tfDzKmpM89DHsNuhgOY4NT6DlNLsTFcuQ' + } + header = SimpleOAuth::Header.new(:post, 'https://api.twitter.com/1/statuses/update.json', {:status => 'hi, again'}, options) + expect(header.to_s).to eq 'OAuth oauth_consumer_key="8karQBlMg6gFOwcf8kcoYw", oauth_nonce="b40a3e0f18590ecdcc0e273f7d7c82f8", oauth_signature="mPqSFKejrWWk3ZT9bTQjhO5b2xI%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1286830181", oauth_token="201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh", oauth_version="1.0"' + end + end + + describe "#secret" do + let(:header){ SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) } + let(:secret){ header.send(:secret) } + + it "combines the consumer and token secrets with an ampersand" do + header.stub(:options => {:consumer_secret => 'CONSUMER_SECRET', :token_secret => 'TOKEN_SECRET'}) + expect(secret).to eq 'CONSUMER_SECRET&TOKEN_SECRET' + end + + it "URI encodes each secret value before combination" do + header.stub(:options => {:consumer_secret => 'CONSUM#R_SECRET', :token_secret => 'TOKEN_S#CRET'}) + expect(secret).to eq 'CONSUM%23R_SECRET&TOKEN_S%23CRET' + end + end + + describe "#signature_base" do + let(:header){ SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) } + let(:signature_base){ header.send(:signature_base) } + + it "combines the request method, URL and normalized parameters using ampersands" do + header.stub(:method => 'METHOD', :url => 'URL', :normalized_params => 'NORMALIZED_PARAMS') + expect(signature_base).to eq 'METHOD&URL&NORMALIZED_PARAMS' + end + + it "URI encodes each value before combination" do + header.stub(:method => 'ME#HOD', :url => 'U#L', :normalized_params => 'NORMAL#ZED_PARAMS') + expect(signature_base).to eq 'ME%23HOD&U%23L&NORMAL%23ZED_PARAMS' + end + end + + describe "#normalized_params" do + let(:header) do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) + header.stub(:signature_params => [['A', '4'], ['B', '3'], ['B', '2'], ['C', '1'], ['D[]', '0 ']]) + header + end + let(:signature_params){ header.send(:signature_params) } + let(:normalized_params){ header.send(:normalized_params) } + + it "joins key/value pairs with equal signs and ampersands" do + expect(normalized_params).to be_a(String) + parts = normalized_params.split('&') + expect(parts.size).to eq signature_params.size + pairs = parts.map{|p| p.split('=') } + expect(pairs).to be_all{|p| p.size == 2 } + end + end + + describe "#signature_params" do + let(:header){ SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) } + let(:signature_params){ header.send(:signature_params) } + + it "combines OAuth header attributes, body parameters and URL parameters into an flattened array of key/value pairs" do + header.stub( + :attributes => {:attribute => 'ATTRIBUTE'}, + :params => {'param' => 'PARAM'}, + :url_params => [['url_param', '1'], ['url_param', '2']] + ) + expect(signature_params).to eq [ + [:attribute, 'ATTRIBUTE'], + ['param', 'PARAM'], + ['url_param', '1'], + ['url_param', '2'] + ] + end + end + + describe "#url_params" do + it "returns an empty array when the URL has no query parameters" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) + expect(header.send(:url_params)).to eq [] + end + + it "returns an array of key/value pairs for each query parameter" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json?test=TEST', {}) + expect(header.send(:url_params)).to eq [['test', 'TEST']] + end + + it "sorts values for repeated keys" do + header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json?test=3&test=1&test=2', {}) + expect(header.send(:url_params)).to eq [['test', '1'], ['test', '2'], ['test', '3']] + end + end + + describe "#rsa_sha1_signature" do + it "reproduces a successful OAuth example GET" do + options = { + :consumer_key => 'dpf43f3p2l4k3l03', + :consumer_secret => rsa_private_key, + :nonce => '13917289812797014437', + :signature_method => 'RSA-SHA1', + :timestamp => '1196666512' + } + header = SimpleOAuth::Header.new(:get, 'http://photos.example.net/photos', {:file => 'vacaction.jpg', :size => 'original'}, options) + expect(header.to_s).to eq 'OAuth oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="13917289812797014437", oauth_signature="jvTp%2FwX1TYtByB1m%2BPbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2%2F9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW%2F%2Fe%2BRinhejgCuzoH26dyF8iY2ZZ%2F5D1ilgeijhV%2FvBka5twt399mXwaYdCwFYE%3D", oauth_signature_method="RSA-SHA1", oauth_timestamp="1196666512", oauth_version="1.0"' + end + end + + describe "#private_key" do + pending + end + + describe "#plaintext_signature" do + it "reproduces a successful OAuth example GET" do + options = { + :consumer_key => 'abcd', + :consumer_secret => 'efgh', + :nonce => 'oLKtec51GQy', + :signature_method => 'PLAINTEXT', + :timestamp => '1286977095', + :token => 'ijkl', + :token_secret => 'mnop' + } + header = SimpleOAuth::Header.new(:get, 'http://host.net/resource?name=value', {:name => 'value'}, options) + expect(header.to_s).to eq 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + end + end +end diff --git a/.gems/gems/simple_oauth-0.2.0/spec/support/fixtures/rsa-private-key b/.gems/gems/simple_oauth-0.2.0/spec/support/fixtures/rsa-private-key new file mode 100644 index 0000000..e0f5542 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/spec/support/fixtures/rsa-private-key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V +A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d +7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ +hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H +X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm +uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw +rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z +zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn +qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG +WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno +cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+ +3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8 +AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54 +Lw03eHTNQghS0A== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/.gems/gems/simple_oauth-0.2.0/spec/support/rsa.rb b/.gems/gems/simple_oauth-0.2.0/spec/support/rsa.rb new file mode 100644 index 0000000..0d3f116 --- /dev/null +++ b/.gems/gems/simple_oauth-0.2.0/spec/support/rsa.rb @@ -0,0 +1,11 @@ +module RSAHelpers + PRIVATE_KEY_PATH = File.expand_path('../fixtures/rsa-private-key', __FILE__) + + def rsa_private_key + @rsa_private_key ||= File.read(PRIVATE_KEY_PATH) + end +end + +RSpec.configure do |config| + config.include RSAHelpers +end diff --git a/.gems/gems/thread_safe-0.3.4/.travis.yml b/.gems/gems/thread_safe-0.3.4/.travis.yml new file mode 100644 index 0000000..0d087fd --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/.travis.yml @@ -0,0 +1,24 @@ +language: ruby +rvm: + - jruby-18mode + - jruby-19mode + - rbx-2 + - 1.8.7 + - 1.9.3 + - 2.0.0 + - 2.1.0 +jdk: # for JRuby only + - openjdk7 + - oraclejdk8 +matrix: + exclude: + - rvm: rbx-2 + jdk: oraclejdk8 + - rvm: 1.8.7 + jdk: oraclejdk8 + - rvm: 1.9.3 + jdk: oraclejdk8 + - rvm: 2.0.0 + jdk: oraclejdk8 + - rvm: 2.1.0 + jdk: oraclejdk8 \ No newline at end of file diff --git a/.gems/gems/thread_safe-0.3.4/Gemfile b/.gems/gems/thread_safe-0.3.4/Gemfile new file mode 100644 index 0000000..fa65970 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in thread_safe.gemspec +gemspec diff --git a/.gems/gems/thread_safe-0.3.4/LICENSE b/.gems/gems/thread_safe-0.3.4/LICENSE new file mode 100644 index 0000000..5336718 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/LICENSE @@ -0,0 +1,144 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as +defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that +is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that +control, are controlled by, or are under common control with that entity. For the purposes +of this definition, "control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by +this License. + +"Source" form shall mean the preferred form for making modifications, including but not +limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of +a Source form, including but not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available +under the License, as indicated by a copyright notice that is included in or attached to the +work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on +(or derived from) the Work and for which the editorial revisions, annotations, elaborations, +or other modifications represent, as a whole, an original work of authorship. For the +purposes of this License, Derivative Works shall not include works that remain separable +from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works +thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work +and any modifications or additions to that Work or Derivative Works thereof, that is +intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by +an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and issue tracking +systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and +improving the Work, but excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a +Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such Derivative +Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license +applies only to those patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or +a Contribution incorporated within the Work constitutes direct or contributory patent +infringement, then any patent licenses granted to You under this License for that Work shall +terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or Object form, provided +that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; +and + +You must cause any modified files to carry prominent notices stating that You changed the +files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all +copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative +Works that You distribute must include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a NOTICE text file +distributed as part of the Derivative Works; within the Source form or documentation, if +provided along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may add Your own +attribution notices within Derivative Works that You distribute, alongside or as an addendum +to the NOTICE text from the Work, provided that such additional attribution notices cannot +be construed as modifying the License. You may add Your own copyright statement to Your +modifications and may provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution +intentionally submitted for inclusion in the Work by You to the Licensor shall be under the +terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for reasonable and +customary use in describing the origin of the Work and reproducing the content of the NOTICE +file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, +Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for +determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort +(including negligence), contract, or otherwise, unless required by applicable law (such as +deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this License or out of the use +or inability to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative +Works thereof, You may choose to offer, and charge a fee for, acceptance of support, +warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on +Your sole responsibility, not on behalf of any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred by, or +claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability. + +END OF TERMS AND CONDITIONS diff --git a/.gems/gems/thread_safe-0.3.4/README.md b/.gems/gems/thread_safe-0.3.4/README.md new file mode 100644 index 0000000..3f964f5 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/README.md @@ -0,0 +1,56 @@ +# Threadsafe + +[![Build Status](https://travis-ci.org/headius/thread_safe.png)](https://travis-ci.org/headius/thread_safe) + +A collection of thread-safe versions of common core Ruby classes. + +## Installation + +Add this line to your application's Gemfile: + + gem 'thread_safe' + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install thread_safe + +## Usage + +```ruby +require 'thread_safe' + +sa = ThreadSafe::Array.new # supports standard Array.new forms +sh = ThreadSafe::Hash.new # supports standard Hash.new forms +``` + +`ThreadSafe::Cache` also exists, as a hash-like object, and should have +much better performance characteristics esp. under high concurrency than +`ThreadSafe::Hash`. However, `ThreadSafe::Cache` is not strictly semantically +equivalent to a ruby `Hash` -- for instance, it does not necessarily retain +ordering by insertion time as `Hash` does. For most uses it should do fine +though, and we recommend you consider `ThreadSafe::Cache` instead of +`ThreadSafe::Hash` for your concurrency-safe hash needs. It understands some +options when created (depending on your ruby platform) that control some of the +internals - when unsure just leave them out: + + +```ruby +require 'thread_safe' + +cache = ThreadSafe::Cache.new +``` + +## Contributing + +1. Fork it +2. Clone it (`git clone git@github.com:you/thread_safe.git`) +3. Create your feature branch (`git checkout -b my-new-feature`) +4. Build the jar (`rake jar`) NOTE: Requires JRuby +5. Install dependencies (`bundle install`) +6. Commit your changes (`git commit -am 'Added some feature'`) +7. Push to the branch (`git push origin my-new-feature`) +8. Create new Pull Request diff --git a/.gems/gems/thread_safe-0.3.4/Rakefile b/.gems/gems/thread_safe-0.3.4/Rakefile new file mode 100644 index 0000000..8717d2f --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/Rakefile @@ -0,0 +1,48 @@ +require "bundler/gem_tasks" +require "rake/testtask" + +task :default => :test + +if defined?(JRUBY_VERSION) + require "ant" + + directory "pkg/classes" + directory 'pkg/tests' + + desc "Clean up build artifacts" + task :clean do + rm_rf "pkg/classes" + rm_rf "pkg/tests" + rm_rf "lib/thread_safe/jruby_cache_backend.jar" + end + + desc "Compile the extension" + task :compile => "pkg/classes" do |t| + ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, + :source => "1.5", :target => "1.5", :debug => true, + :classpath => "${java.class.path}:${sun.boot.class.path}" + end + + desc "Build the jar" + task :jar => :compile do + ant.jar :basedir => "pkg/classes", :destfile => "lib/thread_safe/jruby_cache_backend.jar", :includes => "**/*.class" + end + + desc "Build test jar" + task 'test-jar' => 'pkg/tests' do |t| + ant.javac :srcdir => 'test/src', :destdir => t.prerequisites.first, + :source => "1.5", :target => "1.5", :debug => true + + ant.jar :basedir => 'pkg/tests', :destfile => 'test/package.jar', :includes => '**/*.class' + end + + task :package => [ :jar, 'test-jar' ] +else + # No need to package anything for non-jruby rubies + task :package +end + +Rake::TestTask.new :test => :package do |t| + t.libs << "lib" + t.test_files = FileList["test/**/*.rb"] +end diff --git a/.gems/gems/thread_safe-0.3.4/examples/bench_cache.rb b/.gems/gems/thread_safe-0.3.4/examples/bench_cache.rb new file mode 100755 index 0000000..14171c9 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/examples/bench_cache.rb @@ -0,0 +1,35 @@ +#!/usr/bin/env ruby -wKU + +require "benchmark" +require "thread_safe" + +hash = {} +cache = ThreadSafe::Cache.new + +ENTRIES = 10_000 + +ENTRIES.times do |i| + hash[i] = i + cache[i] = i +end + +TESTS = 40_000_000 +Benchmark.bmbm do |results| + key = rand(10_000) + + results.report('Hash#[]') do + TESTS.times { hash[key] } + end + + results.report('Cache#[]') do + TESTS.times { cache[key] } + end + + results.report('Hash#each_pair') do + (TESTS / ENTRIES).times { hash.each_pair {|k,v| v} } + end + + results.report('Cache#each_pair') do + (TESTS / ENTRIES).times { cache.each_pair {|k,v| v} } + end +end diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java new file mode 100644 index 0000000..8ff7b64 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java @@ -0,0 +1,245 @@ +package org.jruby.ext.thread_safe; + +import org.jruby.*; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.thread_safe.jsr166e.ConcurrentHashMap; +import org.jruby.ext.thread_safe.jsr166e.ConcurrentHashMapV8; +import org.jruby.ext.thread_safe.jsr166e.nounsafe.*; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +import java.io.IOException; +import java.util.Map; + +import static org.jruby.runtime.Visibility.PRIVATE; + +/** + * Native Java implementation to avoid the JI overhead. + * + * @author thedarkone + */ +public class JRubyCacheBackendLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyClass jrubyRefClass = runtime.defineClassUnder("JRubyCacheBackend", runtime.getObject(), BACKEND_ALLOCATOR, runtime.getModule("ThreadSafe")); + jrubyRefClass.setAllocator(BACKEND_ALLOCATOR); + jrubyRefClass.defineAnnotatedMethods(JRubyCacheBackend.class); + } + + private static final ObjectAllocator BACKEND_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyCacheBackend(runtime, klazz); + } + }; + + @JRubyClass(name="JRubyCacheBackend", parent="Object") + public static class JRubyCacheBackend extends RubyObject { + // Defaults used by the CHM + static final int DEFAULT_INITIAL_CAPACITY = 16; + static final float DEFAULT_LOAD_FACTOR = 0.75f; + + public static final boolean CAN_USE_UNSAFE_CHM = canUseUnsafeCHM(); + + private ConcurrentHashMap map; + + private static ConcurrentHashMap newCHM(int initialCapacity, float loadFactor) { + if (CAN_USE_UNSAFE_CHM) { + return new ConcurrentHashMapV8(initialCapacity, loadFactor); + } else { + return new org.jruby.ext.thread_safe.jsr166e.nounsafe.ConcurrentHashMapV8(initialCapacity, loadFactor); + } + } + + private static ConcurrentHashMap newCHM() { + return newCHM(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); + } + + private static boolean canUseUnsafeCHM() { + try { + new org.jruby.ext.thread_safe.jsr166e.ConcurrentHashMapV8(); // force class load and initialization + return true; + } catch (Throwable t) { // ensuring we really do catch everything + // Doug's Unsafe setup errors always have this "Could not ini.." message + if (t.getMessage().contains("Could not initialize intrinsics") || isCausedBySecurityException(t)) { + return false; + } + throw (t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t)); + } + } + + private static boolean isCausedBySecurityException(Throwable t) { + while (t != null) { + if (t instanceof SecurityException) { + return true; + } + t = t.getCause(); + } + return false; + } + + public JRubyCacheBackend(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + map = newCHM(); + return context.getRuntime().getNil(); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject options) { + map = toCHM(context, options); + return context.getRuntime().getNil(); + } + + private ConcurrentHashMap toCHM(ThreadContext context, IRubyObject options) { + Ruby runtime = context.getRuntime(); + if (!options.isNil() && options.respondsTo("[]")) { + IRubyObject rInitialCapacity = options.callMethod(context, "[]", runtime.newSymbol("initial_capacity")); + IRubyObject rLoadFactor = options.callMethod(context, "[]", runtime.newSymbol("load_factor")); + int initialCapacity = !rInitialCapacity.isNil() ? RubyNumeric.num2int(rInitialCapacity.convertToInteger()) : DEFAULT_INITIAL_CAPACITY; + float loadFactor = !rLoadFactor.isNil() ? (float)RubyNumeric.num2dbl(rLoadFactor.convertToFloat()) : DEFAULT_LOAD_FACTOR; + return newCHM(initialCapacity, loadFactor); + } else { + return newCHM(); + } + } + + @JRubyMethod(name = "[]", required = 1) + public IRubyObject op_aref(ThreadContext context, IRubyObject key) { + IRubyObject value; + return ((value = map.get(key)) == null) ? context.getRuntime().getNil() : value; + } + + @JRubyMethod(name = {"[]="}, required = 2) + public IRubyObject op_aset(IRubyObject key, IRubyObject value) { + map.put(key, value); + return value; + } + + @JRubyMethod + public IRubyObject put_if_absent(IRubyObject key, IRubyObject value) { + IRubyObject result = map.putIfAbsent(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject compute_if_absent(final ThreadContext context, final IRubyObject key, final Block block) { + return map.computeIfAbsent(key, new ConcurrentHashMap.Fun() { + @Override + public IRubyObject apply(IRubyObject key) { + return block.yieldSpecific(context); + } + }); + } + + @JRubyMethod + public IRubyObject compute_if_present(final ThreadContext context, final IRubyObject key, final Block block) { + IRubyObject result = map.computeIfPresent(key, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject compute(final ThreadContext context, final IRubyObject key, final Block block) { + IRubyObject result = map.compute(key, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject merge_pair(final ThreadContext context, final IRubyObject key, final IRubyObject value, final Block block) { + IRubyObject result = map.merge(key, value, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject oldValue, IRubyObject newValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObject newValue) { + return getRuntime().newBoolean(map.replace(key, oldValue, newValue)); + } + + @JRubyMethod(name = "key?", required = 1) + public RubyBoolean has_key_p(IRubyObject key) { + return map.containsKey(key) ? getRuntime().getTrue() : getRuntime().getFalse(); + } + + @JRubyMethod + public IRubyObject key(IRubyObject value) { + final IRubyObject key = map.findKey(value); + return key == null ? getRuntime().getNil() : key; + } + + @JRubyMethod + public IRubyObject replace_if_exists(IRubyObject key, IRubyObject value) { + IRubyObject result = map.replace(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject get_and_set(IRubyObject key, IRubyObject value) { + IRubyObject result = map.put(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject delete(IRubyObject key) { + IRubyObject result = map.remove(key); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public RubyBoolean delete_pair(IRubyObject key, IRubyObject value) { + return getRuntime().newBoolean(map.remove(key, value)); + } + + @JRubyMethod + public IRubyObject clear() { + map.clear(); + return this; + } + + @JRubyMethod + public IRubyObject each_pair(ThreadContext context, Block block) { + for (Map.Entry entry : map.entrySet()) { + block.yieldSpecific(context, entry.getKey(), entry.getValue()); + } + return this; + } + + @JRubyMethod + public RubyFixnum size(ThreadContext context) { + return context.getRuntime().newFixnum(map.size()); + } + + @JRubyMethod + public IRubyObject get_or_default(IRubyObject key, IRubyObject defaultValue) { + return map.getValueOrDefault(key, defaultValue); + } + + @JRubyMethod(visibility = PRIVATE) + public JRubyCacheBackend initialize_copy(ThreadContext context, IRubyObject other) { + map = newCHM(); + return this; + } + } +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java new file mode 100644 index 0000000..90ae1a2 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java @@ -0,0 +1,31 @@ +package org.jruby.ext.thread_safe.jsr166e; + +import java.util.Map; +import java.util.Set; + +public interface ConcurrentHashMap { + /** Interface describing a function of one argument */ + public interface Fun { T apply(A a); } + /** Interface describing a function of two arguments */ + public interface BiFun { T apply(A a, B b); } + + public V get(K key); + public V put(K key, V value); + public V putIfAbsent(K key, V value); + public V computeIfAbsent(K key, Fun mf); + public V computeIfPresent(K key, BiFun mf); + public V compute(K key, BiFun mf); + public V merge(K key, V value, BiFun mf); + public boolean replace(K key, V oldVal, V newVal); + public V replace(K key, V value); + public boolean containsKey(K key); + public boolean remove(Object key, Object value); + public V remove(K key); + public void clear(); + public Set> entrySet(); + public int size(); + public V getValueOrDefault(Object key, V defaultValue); + + public boolean containsValue(V value); + public K findKey(V value); +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java new file mode 100644 index 0000000..c85b989 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java @@ -0,0 +1,3863 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on the 1.79 version. + +package org.jruby.ext.thread_safe.jsr166e; + +import org.jruby.RubyClass; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.exceptions.RaiseException; +import org.jruby.ext.thread_safe.jsr166y.ThreadLocalRandom; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +import java.io.Serializable; + +/** + * A hash table supporting full concurrency of retrievals and + * high expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * {@code Hashtable}. However, even though all operations are + * thread-safe, retrieval operations do not entail locking, + * and there is not any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with {@code Hashtable} in programs that rely on its + * thread safety but not on its synchronization details. + * + *

    Retrieval operations (including {@code get}) generally do not + * block, so may overlap with update operations (including {@code put} + * and {@code remove}). Retrievals reflect the results of the most + * recently completed update operations holding upon their + * onset. (More formally, an update operation for a given key bears a + * happens-before relation with any (non-null) retrieval for + * that key reporting the updated value.) For aggregate operations + * such as {@code putAll} and {@code clear}, concurrent retrievals may + * reflect insertion or removal of only some entries. Similarly, + * Iterators and Enumerations return elements reflecting the state of + * the hash table at some point at or since the creation of the + * iterator/enumeration. They do not throw {@link + * ConcurrentModificationException}. However, iterators are designed + * to be used by only one thread at a time. Bear in mind that the + * results of aggregate status methods including {@code size}, {@code + * isEmpty}, and {@code containsValue} are typically useful only when + * a map is not undergoing concurrent updates in other threads. + * Otherwise the results of these methods reflect transient states + * that may be adequate for monitoring or estimation purposes, but not + * for program control. + * + *

    The table is dynamically expanded when there are too many + * collisions (i.e., keys that have distinct hash codes but fall into + * the same slot modulo the table size), with the expected average + * effect of maintaining roughly two bins per mapping (corresponding + * to a 0.75 load factor threshold for resizing). There may be much + * variance around this average as mappings are added and removed, but + * overall, this maintains a commonly accepted time/space tradeoff for + * hash tables. However, resizing this or any other kind of hash + * table may be a relatively slow operation. When possible, it is a + * good idea to provide a size estimate as an optional {@code + * initialCapacity} constructor argument. An additional optional + * {@code loadFactor} constructor argument provides a further means of + * customizing initial table capacity by specifying the table density + * to be used in calculating the amount of space to allocate for the + * given number of elements. Also, for compatibility with previous + * versions of this class, constructors may optionally specify an + * expected {@code concurrencyLevel} as an additional hint for + * internal sizing. Note that using many keys with exactly the same + * {@code hashCode()} is a sure way to slow down performance of any + * hash table. + * + *

    A {@link Set} projection of a ConcurrentHashMapV8 may be created + * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed + * (using {@link #keySet(Object)} when only keys are of interest, and the + * mapped values are (perhaps transiently) not used or all take the + * same mapping value. + * + *

    A ConcurrentHashMapV8 can be used as scalable frequency map (a + * form of histogram or multiset) by using {@link LongAdder} values + * and initializing via {@link #computeIfAbsent}. For example, to add + * a count to a {@code ConcurrentHashMapV8 freqs}, you + * can use {@code freqs.computeIfAbsent(k -> new + * LongAdder()).increment();} + * + *

    This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. + * + *

    Like {@link Hashtable} but unlike {@link HashMap}, this class + * does not allow {@code null} to be used as a key or value. + * + *

    ConcurrentHashMapV8s support parallel operations using the {@link + * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts + * are available in class {@link ForkJoinTasks}). These operations are + * designed to be safely, and often sensibly, applied even with maps + * that are being concurrently updated by other threads; for example, + * when computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and (Key, + * Value) arguments and/or return values. (The first three forms are + * also available via the {@link #keySet()}, {@link #values()} and + * {@link #entrySet()} views). Because the elements of a + * ConcurrentHashMapV8 are not ordered in any particular way, and may be + * processed in different orders in different parallel executions, the + * correctness of supplied functions should not depend on any + * ordering, or on any other objects or values that may transiently + * change while computation is in progress; and except for forEach + * actions, should ideally be side-effect-free. + * + *

      + *
    • forEach: Perform a given action on each element. + * A variant form applies a given transformation on each element + * before performing the action.
    • + * + *
    • search: Return the first available non-null result of + * applying a given function on each element; skipping further + * search when a result is found.
    • + * + *
    • reduce: Accumulate each element. The supplied reduction + * function cannot rely on ordering (more formally, it should be + * both associative and commutative). There are five variants: + * + *
        + * + *
      • Plain reductions. (There is not a form of this method for + * (key, value) function arguments since there is no corresponding + * return type.)
      • + * + *
      • Mapped reductions that accumulate the results of a given + * function applied to each element.
      • + * + *
      • Reductions to scalar doubles, longs, and ints, using a + * given basis value.
      • + * + * + *
      + *
    + * + *

    The concurrency properties of bulk operations follow + * from those of ConcurrentHashMapV8: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

    Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

    Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

    Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

    Parallel speedups for bulk operations compared to sequential + * processing are common but not guaranteed. Operations involving + * brief functions on small maps may execute more slowly than + * sequential loops if the underlying work to parallelize the + * computation is more expensive than the computation itself. + * Similarly, parallelization may not lead to much actual parallelism + * if all processors are busy performing unrelated tasks. + * + *

    All arguments to all task methods must be non-null. + * + *

    jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + * + *

    This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +public class ConcurrentHashMapV8 + implements ConcurrentMap, Serializable, ConcurrentHashMap { + private static final long serialVersionUID = 7249069246763182397L; + + /** + * A partitionable iterator. A Spliterator can be traversed + * directly, but can also be partitioned (before traversal) by + * creating another Spliterator that covers a non-overlapping + * portion of the elements, and so may be amenable to parallel + * execution. + * + *

    This interface exports a subset of expected JDK8 + * functionality. + * + *

    Sample usage: Here is one (of the several) ways to compute + * the sum of the values held in a map using the ForkJoin + * framework. As illustrated here, Spliterators are well suited to + * designs in which a task repeatedly splits off half its work + * into forked subtasks until small enough to process directly, + * and then joins these subtasks. Variants of this style can also + * be used in completion-based designs. + * + *

    +     * {@code ConcurrentHashMapV8 m = ...
    +     * // split as if have 8 * parallelism, for load balance
    +     * int n = m.size();
    +     * int p = aForkJoinPool.getParallelism() * 8;
    +     * int split = (n < p)? n : p;
    +     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
    +     * // ...
    +     * static class SumValues extends RecursiveTask {
    +     *   final Spliterator s;
    +     *   final int split;             // split while > 1
    +     *   final SumValues nextJoin;    // records forked subtasks to join
    +     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
    +     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
    +     *   }
    +     *   public Long compute() {
    +     *     long sum = 0;
    +     *     SumValues subtasks = null; // fork subtasks
    +     *     for (int s = split >>> 1; s > 0; s >>>= 1)
    +     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
    +     *     while (s.hasNext())        // directly process remaining elements
    +     *       sum += s.next();
    +     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
    +     *       sum += t.join();         // collect subtask results
    +     *     return sum;
    +     *   }
    +     * }
    +     * }
    + */ + public static interface Spliterator extends Iterator { + /** + * Returns a Spliterator covering approximately half of the + * elements, guaranteed not to overlap with those subsequently + * returned by this Spliterator. After invoking this method, + * the current Spliterator will not produce any of + * the elements of the returned Spliterator, but the two + * Spliterators together will produce all of the elements that + * would have been produced by this Spliterator had this + * method not been called. The exact number of elements + * produced by the returned Spliterator is not guaranteed, and + * may be zero (i.e., with {@code hasNext()} reporting {@code + * false}) if this Spliterator cannot be further split. + * + * @return a Spliterator covering approximately half of the + * elements + * @throws IllegalStateException if this Spliterator has + * already commenced traversing elements + */ + Spliterator split(); + } + + + /* + * Overview: + * + * The primary design goal of this hash table is to maintain + * concurrent readability (typically method get(), but also + * iterators and related methods) while minimizing update + * contention. Secondary goals are to keep space consumption about + * the same or better than java.util.HashMap, and to support high + * initial insertion rates on an empty table by many threads. + * + * Each key-value mapping is held in a Node. Because Node fields + * can contain special values, they are defined using plain Object + * types. Similarly in turn, all internal methods that use them + * work off Object types. And similarly, so do the internal + * methods of auxiliary iterator and view classes. All public + * generic typed methods relay in/out of these internal methods, + * supplying null-checks and casts as needed. This also allows + * many of the public methods to be factored into a smaller number + * of internal methods (although sadly not so for the five + * variants of put-related operations). The validation-based + * approach explained below leads to a lot of code sprawl because + * retry-control precludes factoring into smaller methods. + * + * The table is lazily initialized to a power-of-two size upon the + * first insertion. Each bin in the table normally contains a + * list of Nodes (most often, the list has only zero or one Node). + * Table accesses require volatile/atomic reads, writes, and + * CASes. Because there is no other way to arrange this without + * adding further indirections, we use intrinsics + * (sun.misc.Unsafe) operations. The lists of nodes within bins + * are always accurately traversable under volatile reads, so long + * as lookups check hash code and non-nullness of value before + * checking key equality. + * + * We use the top two bits of Node hash fields for control + * purposes -- they are available anyway because of addressing + * constraints. As explained further below, these top bits are + * used as follows: + * 00 - Normal + * 01 - Locked + * 11 - Locked and may have a thread waiting for lock + * 10 - Node is a forwarding node + * + * The lower 30 bits of each Node's hash field contain a + * transformation of the key's hash code, except for forwarding + * nodes, for which the lower bits are zero (and so always have + * hash field == MOVED). + * + * Insertion (via put or its variants) of the first node in an + * empty bin is performed by just CASing it to the bin. This is + * by far the most common case for put operations under most + * key/hash distributions. Other update operations (insert, + * delete, and replace) require locks. We do not want to waste + * the space required to associate a distinct lock object with + * each bin, so instead use the first node of a bin list itself as + * a lock. Blocking support for these locks relies on the builtin + * "synchronized" monitors. However, we also need a tryLock + * construction, so we overlay these by using bits of the Node + * hash field for lock control (see above), and so normally use + * builtin monitors only for blocking and signalling using + * wait/notifyAll constructions. See Node.tryAwaitLock. + * + * Using the first node of a list as a lock does not by itself + * suffice though: When a node is locked, any update must first + * validate that it is still the first node after locking it, and + * retry if not. Because new nodes are always appended to lists, + * once a node is first in a bin, it remains first until deleted + * or the bin becomes invalidated (upon resizing). However, + * operations that only conditionally update may inspect nodes + * until the point of update. This is a converse of sorts to the + * lazy locking technique described by Herlihy & Shavit. + * + * The main disadvantage of per-bin locks is that other update + * operations on other nodes in a bin list protected by the same + * lock can stall, for example when user equals() or mapping + * functions take a long time. However, statistically, under + * random hash codes, this is not a common problem. Ideally, the + * frequency of nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average, given the resizing threshold + * of 0.75, although with a large variance because of resizing + * granularity. Ignoring variance, the expected occurrences of + * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + * first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * Lock contention probability for two threads accessing distinct + * elements is roughly 1 / (8 * #elements) under random hashes. + * + * Actual hash code distributions encountered in practice + * sometimes deviate significantly from uniform randomness. This + * includes the case when N > (1<<30), so some keys MUST collide. + * Similarly for dumb or hostile usages in which multiple keys are + * designed to have identical hash codes. Also, although we guard + * against the worst effects of this (see method spread), sets of + * hashes may differ only in bits that do not impact their bin + * index for a given power-of-two mask. So we use a secondary + * strategy that applies when the number of nodes in a bin exceeds + * a threshold, and at least one of the keys implements + * Comparable. These TreeBins use a balanced tree to hold nodes + * (a specialized form of red-black trees), bounding search time + * to O(log N). Each search step in a TreeBin is around twice as + * slow as in a regular list, but given that N cannot exceed + * (1<<64) (before running out of addresses) this bounds search + * steps, lock hold times, etc, to reasonable constants (roughly + * 100 nodes inspected per operation worst case) so long as keys + * are Comparable (which is very common -- String, Long, etc). + * TreeBin nodes (TreeNodes) also maintain the same "next" + * traversal pointers as regular nodes, so can be traversed in + * iterators in the same way. + * + * The table is resized when occupancy exceeds a percentage + * threshold (nominally, 0.75, but see below). Only a single + * thread performs the resize (using field "sizeCtl", to arrange + * exclusion), but the table otherwise remains usable for reads + * and updates. Resizing proceeds by transferring bins, one by + * one, from the table to the next table. Because we are using + * power-of-two expansion, the elements from each bin must either + * stay at same index, or move with a power of two offset. We + * eliminate unnecessary node creation by catching cases where old + * nodes can be reused because their next fields won't change. On + * average, only about one-sixth of them need cloning when a table + * doubles. The nodes they replace will be garbage collectable as + * soon as they are no longer referenced by any reader thread that + * may be in the midst of concurrently traversing table. Upon + * transfer, the old table bin contains only a special forwarding + * node (with hash field "MOVED") that contains the next table as + * its key. On encountering a forwarding node, access and update + * operations restart, using the new table. + * + * Each bin transfer requires its bin lock. However, unlike other + * cases, a transfer can skip a bin if it fails to acquire its + * lock, and revisit it later (unless it is a TreeBin). Method + * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that + * have been skipped because of failure to acquire a lock, and + * blocks only if none are available (i.e., only very rarely). + * The transfer operation must also ensure that all accessible + * bins in both the old and new table are usable by any traversal. + * When there are no lock acquisition failures, this is arranged + * simply by proceeding from the last bin (table.length - 1) up + * towards the first. Upon seeing a forwarding node, traversals + * (see class Iter) arrange to move to the new table + * without revisiting nodes. However, when any node is skipped + * during a transfer, all earlier table bins may have become + * visible, so are initialized with a reverse-forwarding node back + * to the old table until the new ones are established. (This + * sometimes requires transiently locking a forwarding node, which + * is possible under the above encoding.) These more expensive + * mechanics trigger only when necessary. + * + * The traversal scheme also applies to partial traversals of + * ranges of bins (via an alternate Traverser constructor) + * to support partitioned aggregate operations. Also, read-only + * operations give up if ever forwarded to a null table, which + * provides support for shutdown-style clearing, which is also not + * currently implemented. + * + * Lazy table initialization minimizes footprint until first use, + * and also avoids resizings when the first operation is from a + * putAll, constructor with map argument, or deserialization. + * These cases attempt to override the initial capacity settings, + * but harmlessly fail to take effect in cases of races. + * + * The element count is maintained using a LongAdder, which avoids + * contention on updates but can encounter cache thrashing if read + * too frequently during concurrent access. To avoid reading so + * often, resizing is attempted either when a bin lock is + * contended, or upon adding to a bin already holding two or more + * nodes (checked before adding in the xIfAbsent methods, after + * adding in others). Under uniform hash distributions, the + * probability of this occurring at threshold is around 13%, + * meaning that only about 1 in 8 puts check threshold (and after + * resizing, many fewer do so). But this approximation has high + * variance for small table sizes, so we check on any collision + * for sizes <= 64. The bulk putAll operation further reduces + * contention by only committing count updates upon these size + * checks. + * + * Maintaining API and serialization compatibility with previous + * versions of this class introduces several oddities. Mainly: We + * leave untouched but unused constructor arguments refering to + * concurrencyLevel. We accept a loadFactor constructor argument, + * but apply it only to initial table capacity (which is the only + * time that we can guarantee to honor it.) We also declare an + * unused "Segment" class that is instantiated in minimal form + * only when serializing. + */ + + /* ---------------- Constants -------------- */ + + /** + * The largest possible table capacity. This value must be + * exactly 1<<30 to stay within Java array allocation and indexing + * bounds for power of two table sizes, and is further required + * because the top two bits of 32bit hash fields are used for + * control purposes. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default initial table capacity. Must be a power of 2 + * (i.e., at least 1) and at most MAXIMUM_CAPACITY. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The largest possible (non-power of two) array size. + * Needed by toArray and related methods. + */ + static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * The default concurrency level for this table. Unused but + * defined for compatibility with previous versions of this class. + */ + private static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The load factor for this table. Overrides of this value in + * constructors affect only the initial table capacity. The + * actual floating point value isn't normally used -- it is + * simpler to use expressions such as {@code n - (n >>> 2)} for + * the associated resizing threshold. + */ + private static final float LOAD_FACTOR = 0.75f; + + /** + * The buffer size for skipped bins during transfers. The + * value is arbitrary but should be large enough to avoid + * most locking stalls during resizes. + */ + private static final int TRANSFER_BUFFER_SIZE = 32; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. The value reflects the approximate break-even point for + * using tree-based operations. + * Note that Doug's version defaults to 8, but when dealing with + * Ruby objects it is actually beneficial to avoid TreeNodes + * as long as possible as it usually means going into Ruby land. + */ + private static final int TREE_THRESHOLD = 16; + + /* + * Encodings for special uses of Node hash fields. See above for + * explanation. + */ + static final int MOVED = 0x80000000; // hash field for forwarding nodes + static final int LOCKED = 0x40000000; // set/tested only as a bit + static final int WAITING = 0xc0000000; // both bits set/tested together + static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash + + /* ---------------- Fields -------------- */ + + /** + * The array of bins. Lazily initialized upon first insertion. + * Size is always a power of two. Accessed directly by iterators. + */ + transient volatile Node[] table; + + /** + * The counter maintaining number of elements. + */ + private transient final LongAdder counter; + + /** + * Table initialization and resizing control. When negative, the + * table is being initialized or resized. Otherwise, when table is + * null, holds the initial table size to use upon creation, or 0 + * for default. After initialization, holds the next element count + * value upon which to resize the table. + */ + private transient volatile int sizeCtl; + + // views + private transient KeySetView keySet; + private transient ValuesView values; + private transient EntrySetView entrySet; + + /** For serialization compatibility. Null unless serialized; see below */ + private Segment[] segments; + + /* ---------------- Table element access -------------- */ + + /* + * Volatile access methods are used for table elements as well as + * elements of in-progress next table while resizing. Uses are + * null checked by callers, and implicitly bounds-checked, relying + * on the invariants that tab arrays have non-zero size, and all + * indices are masked with (tab.length - 1) which is never + * negative and always less than length. Note that, to be correct + * wrt arbitrary concurrency errors by users, bounds checks must + * operate on local variables, which accounts for some odd-looking + * inline assignments below. + */ + + static final Node tabAt(Node[] tab, int i) { // used by Iter + return (Node)UNSAFE.getObjectVolatile(tab, ((long)i< 1 ? 64 : 1; + + /** + * Spins a while if LOCKED bit set and this node is the first + * of its bin, and then sets WAITING bits on hash field and + * blocks (once) if they are still set. It is OK for this + * method to return even if lock is not available upon exit, + * which enables these simple single-wait mechanics. + * + * The corresponding signalling operation is performed within + * callers: Upon detecting that WAITING has been set when + * unlocking lock (via a failed CAS from non-waiting LOCKED + * state), unlockers acquire the sync lock and perform a + * notifyAll. + * + * The initial sanity check on tab and bounds is not currently + * necessary in the only usages of this method, but enables + * use in other future contexts. + */ + final void tryAwaitLock(Node[] tab, int i) { + if (tab != null && i >= 0 && i < tab.length) { // sanity check + int r = ThreadLocalRandom.current().nextInt(); // randomize spins + int spins = MAX_SPINS, h; + while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { + if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0 && --spins == 0) + Thread.yield(); // yield before block + } + else if (casHash(h, h | WAITING)) { + synchronized (this) { + if (tabAt(tab, i) == this && + (hash & WAITING) == WAITING) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + else + notifyAll(); // possibly won race vs signaller + } + break; + } + } + } + } + + // Unsafe mechanics for casHash + private static final sun.misc.Unsafe UNSAFE; + private static final long hashOffset; + + static { + try { + UNSAFE = getUnsafe(); + Class k = Node.class; + hashOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("hash")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /* ---------------- TreeBins -------------- */ + + /** + * Nodes for use in TreeBins + */ + static final class TreeNode extends Node { + TreeNode parent; // red-black tree links + TreeNode left; + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + + TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { + super(hash, key, val, next); + this.parent = parent; + } + } + + /** + * A specialized form of red-black tree for use in bins + * whose size exceeds a threshold. + * + * TreeBins use a special form of comparison for search and + * related operations (which is the main reason we cannot use + * existing collections such as TreeMaps). TreeBins contain + * Comparable elements, but may contain others, as well as + * elements that are Comparable but not necessarily Comparable + * for the same T, so we cannot invoke compareTo among them. To + * handle this, the tree is ordered primarily by hash value, then + * by getClass().getName() order, and then by Comparator order + * among elements of the same class. On lookup at a node, if + * elements are not comparable or compare as 0, both left and + * right children may need to be searched in the case of tied hash + * values. (This corresponds to the full list search that would be + * necessary if all elements were non-Comparable and had tied + * hashes.) The red-black balancing code is updated from + * pre-jdk-collections + * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) + * based in turn on Cormen, Leiserson, and Rivest "Introduction to + * Algorithms" (CLR). + * + * TreeBins also maintain a separate locking discipline than + * regular bins. Because they are forwarded via special MOVED + * nodes at bin heads (which can never change once established), + * we cannot use those nodes as locks. Instead, TreeBin + * extends AbstractQueuedSynchronizer to support a simple form of + * read-write lock. For update operations and table validation, + * the exclusive form of lock behaves in the same way as bin-head + * locks. However, lookups use shared read-lock mechanics to allow + * multiple readers in the absence of writers. Additionally, + * these lookups do not ever block: While the lock is not + * available, they proceed along the slow traversal path (via + * next-pointers) until the lock becomes available or the list is + * exhausted, whichever comes first. (These cases are not fast, + * but maximize aggregate expected throughput.) The AQS mechanics + * for doing this are straightforward. The lock state is held as + * AQS getState(). Read counts are negative; the write count (1) + * is positive. There are no signalling preferences among readers + * and writers. Since we don't need to export full Lock API, we + * just override the minimal AQS methods and use them directly. + */ + static final class TreeBin extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 2249069246763182397L; + transient TreeNode root; // root of tree + transient TreeNode first; // head of next-pointer list + + /* AQS overrides */ + public final boolean isHeldExclusively() { return getState() > 0; } + public final boolean tryAcquire(int ignore) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + public final boolean tryRelease(int ignore) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + public final int tryAcquireShared(int ignore) { + for (int c;;) { + if ((c = getState()) > 0) + return -1; + if (compareAndSetState(c, c -1)) + return 1; + } + } + public final boolean tryReleaseShared(int ignore) { + int c; + do {} while (!compareAndSetState(c = getState(), c + 1)); + return c == -1; + } + + /** From CLR */ + private void rotateLeft(TreeNode p) { + if (p != null) { + TreeNode r = p.right, pp, rl; + if ((rl = p.right = r.left) != null) + rl.parent = p; + if ((pp = r.parent = p.parent) == null) + root = r; + else if (pp.left == p) + pp.left = r; + else + pp.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeNode p) { + if (p != null) { + TreeNode l = p.left, pp, lr; + if ((lr = p.left = l.right) != null) + lr.parent = p; + if ((pp = l.parent = p.parent) == null) + root = l; + else if (pp.right == p) + pp.right = l; + else + pp.left = l; + l.right = p; + p.parent = l; + } + } + + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, Object k, TreeNode p) { + return getTreeNode(h, (RubyObject)k, p); + } + + /** + * Returns the TreeNode (or null if not found) for the given key + * starting at given root. + */ + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, RubyObject k, TreeNode p) { + RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); + while (p != null) { + int dir, ph; RubyObject pk; RubyClass pc; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = (RubyClass)pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pl, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + // try to continue iterating on the left side + else if ((pl = p.left) != null && h <= pl.hash) + dir = -1; + else // no matching node found + return null; + } + } + } + else + dir = (h < ph) ? -1 : 1; + p = (dir > 0) ? p.right : p.left; + } + return null; + } + + int rubyCompare(RubyObject l, RubyObject r) { + ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); + IRubyObject result; + try { + result = l.callMethod(context, "<=>", r); + } catch (RaiseException e) { + // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys + if (context.runtime.getNoMethodError().isInstance(e.getException())) { + return 0; + } + throw e; + } + + return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); + } + + /** + * Wrapper for getTreeNode used by CHM.get. Tries to obtain + * read-lock to call getTreeNode, but during failure to get + * lock, searches along next links. + */ + final Object getValue(int h, Object k) { + Node r = null; + int c = getState(); // Must read lock state first + for (Node e = first; e != null; e = e.next) { + if (c <= 0 && compareAndSetState(c, c - 1)) { + try { + r = getTreeNode(h, k, root); + } finally { + releaseShared(0); + } + break; + } + else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { + r = e; + break; + } + else + c = getState(); + } + return r == null ? null : r.val; + } + + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, Object k, Object v) { + return putTreeNode(h, (RubyObject)k, v); + } + + /** + * Finds or adds a node. + * @return null if added + */ + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, RubyObject k, Object v) { + RubyClass c = k.getMetaClass(); + boolean kNotComparable = !k.respondsTo("<=>"); + TreeNode pp = root, p = null; + int dir = 0; + while (pp != null) { // find existing node or leaf to insert at + int ph; RubyObject pk; RubyClass pc; + p = pp; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + else // continue descending down the left subtree + dir = -1; + } + } + } + else + dir = (h < ph) ? -1 : 1; + pp = (dir > 0) ? p.right : p.left; + } + + TreeNode f = first; + TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); + if (p == null) + root = x; + else { // attach and rebalance; adapted from CLR + TreeNode xp, xpp; + if (f != null) + f.prev = x; + if (dir <= 0) + p.left = x; + else + p.right = x; + x.red = true; + while (x != null && (xp = x.parent) != null && xp.red && + (xpp = xp.parent) != null) { + TreeNode xppl = xpp.left; + if (xp == xppl) { + TreeNode y = xpp.right; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.right) { + rotateLeft(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateRight(xpp); + } + } + } + } + else { + TreeNode y = xppl; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.left) { + rotateRight(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateLeft(xpp); + } + } + } + } + } + TreeNode r = root; + if (r != null && r.red) + r.red = false; + } + return null; + } + + /** + * Removes the given node, that must be present before this + * call. This is messier than typical red-black deletion code + * because we cannot swap the contents of an interior node + * with a leaf successor that is pinned by "next" pointers + * that are accessible independently of lock. So instead we + * swap the tree linkages. + */ + final void deleteTreeNode(TreeNode p) { + TreeNode next = (TreeNode)p.next; // unlink traversal pointers + TreeNode pred = p.prev; + if (pred == null) + first = next; + else + pred.next = next; + if (next != null) + next.prev = pred; + TreeNode replacement; + TreeNode pl = p.left; + TreeNode pr = p.right; + if (pl != null && pr != null) { + TreeNode s = pr, sl; + while ((sl = s.left) != null) // find successor + s = sl; + boolean c = s.red; s.red = p.red; p.red = c; // swap colors + TreeNode sr = s.right; + TreeNode pp = p.parent; + if (s == pr) { // p was s's direct parent + p.parent = s; + s.right = p; + } + else { + TreeNode sp = s.parent; + if ((p.parent = sp) != null) { + if (s == sp.left) + sp.left = p; + else + sp.right = p; + } + if ((s.right = pr) != null) + pr.parent = s; + } + p.left = null; + if ((p.right = sr) != null) + sr.parent = p; + if ((s.left = pl) != null) + pl.parent = s; + if ((s.parent = pp) == null) + root = s; + else if (p == pp.left) + pp.left = s; + else + pp.right = s; + replacement = sr; + } + else + replacement = (pl != null) ? pl : pr; + TreeNode pp = p.parent; + if (replacement == null) { + if (pp == null) { + root = null; + return; + } + replacement = p; + } + else { + replacement.parent = pp; + if (pp == null) + root = replacement; + else if (p == pp.left) + pp.left = replacement; + else + pp.right = replacement; + p.left = p.right = p.parent = null; + } + if (!p.red) { // rebalance, from CLR + TreeNode x = replacement; + while (x != null) { + TreeNode xp, xpl; + if (x.red || (xp = x.parent) == null) { + x.red = false; + break; + } + if (x == (xpl = xp.left)) { + TreeNode sib = xp.right; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateLeft(xp); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sr == null || !sr.red) && + (sl == null || !sl.red)) { + sib.red = true; + x = xp; + } + else { + if (sr == null || !sr.red) { + if (sl != null) + sl.red = false; + sib.red = true; + rotateRight(sib); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sr = sib.right) != null) + sr.red = false; + } + if (xp != null) { + xp.red = false; + rotateLeft(xp); + } + x = root; + } + } + } + else { // symmetric + TreeNode sib = xpl; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateRight(xp); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sl == null || !sl.red) && + (sr == null || !sr.red)) { + sib.red = true; + x = xp; + } + else { + if (sl == null || !sl.red) { + if (sr != null) + sr.red = false; + sib.red = true; + rotateLeft(sib); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sl = sib.left) != null) + sl.red = false; + } + if (xp != null) { + xp.red = false; + rotateRight(xp); + } + x = root; + } + } + } + } + } + if (p == replacement && (pp = p.parent) != null) { + if (p == pp.left) // detach pointers + pp.left = null; + else if (p == pp.right) + pp.right = null; + p.parent = null; + } + } + } + + /* ---------------- Collision reduction methods -------------- */ + + /** + * Spreads higher bits to lower, and also forces top 2 bits to 0. + * Because the table uses power-of-two masking, sets of hashes + * that vary only in bits above the current mask will always + * collide. (Among known examples are sets of Float keys holding + * consecutive whole numbers in small tables.) To counter this, + * we apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed across bits (so don't benefit + * from spreading), and because we use trees to handle large sets + * of collisions in bins, we don't need excessively high quality. + */ + private static final int spread(int h) { + h ^= (h >>> 18) ^ (h >>> 12); + return (h ^ (h >>> 10)) & HASH_BITS; + } + + /** + * Replaces a list bin with a tree bin. Call only when locked. + * Fails to replace if the given key is non-comparable or table + * is, or needs, resizing. + */ + private final void replaceWithTreeBin(Node[] tab, int index, Object key) { + if ((key instanceof Comparable) && + (tab.length >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { + TreeBin t = new TreeBin(); + for (Node e = tabAt(tab, index); e != null; e = e.next) + t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); + setTabAt(tab, index, new Node(MOVED, t, null, null)); + } + } + + /* ---------------- Internal access and update methods -------------- */ + + /** Implementation for get and containsKey */ + private final Object internalGet(Object k) { + int h = spread(k.hashCode()); + retry: for (Node[] tab = table; tab != null;) { + Node e, p; Object ek, ev; int eh; // locals to read fields once + for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) { + if ((eh = e.hash) == MOVED) { + if ((ek = e.key) instanceof TreeBin) // search TreeBin + return ((TreeBin)ek).getValue(h, k); + else { // restart with new table + tab = (Node[])ek; + continue retry; + } + } + else if ((eh & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + } + break; + } + return null; + } + + /** + * Implementation for the four public remove/replace methods: + * Replaces node value with v, conditional upon match of cv if + * non-null. If resulting value is null, delete. + */ + private final Object internalReplace(Object k, Object v, Object cv) { + int h = spread(k.hashCode()); + Object oldVal = null; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null || + (f = tabAt(tab, i = (tab.length - 1) & h)) == null) + break; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + boolean deleted = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) { + Object pv = p.val; + if (cv == null || cv == pv || cv.equals(pv)) { + oldVal = pv; + if ((p.val = v) == null) { + deleted = true; + t.deleteTreeNode(p); + } + } + } + } + } finally { + t.release(0); + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) != h && f.next == null) // precheck + break; // rules out possible existence + else if ((fh & LOCKED) != 0) { + checkForResize(); // try resizing if can't get lock + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + boolean validated = false; + boolean deleted = false; + try { + if (tabAt(tab, i) == f) { + validated = true; + for (Node e = f, pred = null;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + ((ev = e.val) != null) && + ((ek = e.key) == k || k.equals(ek))) { + if (cv == null || cv == ev || cv.equals(ev)) { + oldVal = ev; + if ((e.val = v) == null) { + deleted = true; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + } + break; + } + pred = e; + if ((e = e.next) == null) + break; + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + } + return oldVal; + } + + /* + * Internal versions of the six insertion methods, each a + * little more complicated than the last. All have + * the same basic structure as the first (internalPut): + * 1. If table uninitialized, create + * 2. If bin empty, try to CAS new node + * 3. If bin stale, use new table + * 4. if bin converted to TreeBin, validate and relay to TreeBin methods + * 5. Lock and validate; if valid, scan and add or update + * + * The others interweave other checks and/or alternative actions: + * * Plain put checks for and performs resize after insertion. + * * putIfAbsent prescans for mapping without lock (and fails to add + * if present), which also makes pre-emptive resize checks worthwhile. + * * computeIfAbsent extends form used in putIfAbsent with additional + * mechanics to deal with, calls, potential exceptions and null + * returns from function call. + * * compute uses the same function-call mechanics, but without + * the prescans + * * merge acts as putIfAbsent in the absent case, but invokes the + * update function if present + * * putAll attempts to pre-allocate enough table space + * and more lazily performs count updates and checks. + * + * Someday when details settle down a bit more, it might be worth + * some factoring to reduce sprawl. + */ + + /** Implementation for put */ + private final Object internalPut(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; // no lock when adding to empty bin + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) { + oldVal = p.val; + p.val = v; + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { // needed in case equals() throws + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { // unlock and signal if needed + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length <= 64) + count = 2; + break; + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for putIfAbsent */ + private final Object internalPutIfAbsent(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) + oldVal = p.val; + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { // at least 2 nodes -- search and maybe resize + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length <= 64) + count = 2; + break; + } + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for computeIfAbsent */ + private final Object internalComputeIfAbsent(K k, + Fun mf) { + int h = spread(k.hashCode()); + Object val = null; + int count = 0; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + count = 1; + try { + if ((val = mf.apply(k)) != null) + node.val = val; + } finally { + if (val == null) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean added = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + val = p.val; + else if ((val = mf.apply(k)) != null) { + added = true; + count = 2; + t.putTreeNode(h, k, val); + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (!added) + return val; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + boolean added = false; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + if ((val = mf.apply(k)) != null) { + added = true; + last.next = new Node(h, k, val, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (!added) + return val; + if (tab.length <= 64) + count = 2; + break; + } + } + } + } + if (val != null) { + counter.add(1L); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for compute */ + @SuppressWarnings("unchecked") private final Object internalCompute + (K k, boolean onlyIfPresent, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (onlyIfPresent) + break; + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + try { + count = 1; + if ((val = mf.apply(k, null)) != null) { + node.val = val; + delta = 1; + } + } finally { + if (delta == 0) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + Object pv; + if (p == null) { + if (onlyIfPresent) + break; + pv = null; + } else + pv = p.val; + if ((val = mf.apply(k, (V)pv)) != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply(k, (V)ev); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for merge */ + @SuppressWarnings("unchecked") private final Object internalMerge + (K k, V v, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + delta = 1; + val = v; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + val = (p == null) ? v : mf.apply((V)p.val, v); + if (val != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply((V)ev, v); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + val = v; + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for putAll */ + private final void internalPutAll(Map m) { + tryPresize(m.size()); + long delta = 0L; // number of uncommitted additions + boolean npe = false; // to throw exception on exit for nulls + try { // to clean up counts on other exceptions + for (Map.Entry entry : m.entrySet()) { + Object k, v; + if (entry == null || (k = entry.getKey()) == null || + (v = entry.getValue()) == null) { + npe = true; + break; + } + int h = spread(k.hashCode()); + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null){ + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + ++delta; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + p.val = v; + else { + t.putTreeNode(h, k, v); + ++delta; + } + } + } finally { + t.release(0); + } + if (validated) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); + delta = 0L; + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + int count = 0; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + ++delta; + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (count > 1) { + counter.add(delta); + delta = 0L; + checkForResize(); + } + break; + } + } + } + } + } finally { + if (delta != 0) + counter.add(delta); + } + if (npe) + throw new NullPointerException(); + } + + /* ---------------- Table Initialization and Resizing -------------- */ + + /** + * Returns a power of two table size for the given desired capacity. + * See Hackers Delight, sec 3.2 + */ + private static final int tableSizeFor(int c) { + int n = c - 1; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + } + + /** + * Initializes table, using the size recorded in sizeCtl. + */ + private final Node[] initTable() { + Node[] tab; int sc; + while ((tab = table) == null) { + if ((sc = sizeCtl) < 0) + Thread.yield(); // lost initialization race; just spin + else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if ((tab = table) == null) { + int n = (sc > 0) ? sc : DEFAULT_CAPACITY; + tab = table = new Node[n]; + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + break; + } + } + return tab; + } + + /** + * If table is too small and not already resizing, creates next + * table and transfers bins. Rechecks occupancy after a transfer + * to see if another resize is already needed because resizings + * are lagging additions. + */ + private final void checkForResize() { + Node[] tab; int n, sc; + while ((tab = table) != null && + (n = tab.length) < MAXIMUM_CAPACITY && + (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && + UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (tab == table) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + + /** + * Tries to presize table to accommodate the given number of elements. + * + * @param size number of elements (doesn't need to be perfectly accurate) + */ + private final void tryPresize(int size) { + int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : + tableSizeFor(size + (size >>> 1) + 1); + int sc; + while ((sc = sizeCtl) >= 0) { + Node[] tab = table; int n; + if (tab == null || (n = tab.length) == 0) { + n = (sc > c) ? sc : c; + if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == tab) { + table = new Node[n]; + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + } + } + else if (c <= sc || n >= MAXIMUM_CAPACITY) + break; + else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == tab) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + } + + /* + * Moves and/or copies the nodes in each bin to new table. See + * above for explanation. + * + * @return the new table + */ + private static final Node[] rebuild(Node[] tab) { + int n = tab.length; + Node[] nextTab = new Node[n << 1]; + Node fwd = new Node(MOVED, nextTab, null, null); + int[] buffer = null; // holds bins to revisit; null until needed + Node rev = null; // reverse forwarder; null until needed + int nbuffered = 0; // the number of bins in buffer list + int bufferIndex = 0; // buffer index of current buffered bin + int bin = n - 1; // current non-buffered bin or -1 if none + + for (int i = bin;;) { // start upwards sweep + int fh; Node f; + if ((f = tabAt(tab, i)) == null) { + if (bin >= 0) { // Unbuffered; no lock needed (or available) + if (!casTabAt(tab, i, f, fwd)) + continue; + } + else { // transiently use a locked forwarding node + Node g = new Node(MOVED|LOCKED, nextTab, null, null); + if (!casTabAt(tab, i, f, g)) + continue; + setTabAt(nextTab, i, null); + setTabAt(nextTab, i + n, null); + setTabAt(tab, i, fwd); + if (!g.casHash(MOVED|LOCKED, MOVED)) { + g.hash = MOVED; + synchronized (g) { g.notifyAll(); } + } + } + } + else if ((fh = f.hash) == MOVED) { + Object fk = f.key; + if (fk instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + splitTreeBin(nextTab, i, t); + setTabAt(tab, i, fwd); + } + } finally { + t.release(0); + } + if (!validated) + continue; + } + } + else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { + boolean validated = false; + try { // split to lo and hi lists; copying as needed + if (tabAt(tab, i) == f) { + validated = true; + splitBin(nextTab, i, f); + setTabAt(tab, i, fwd); + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (!validated) + continue; + } + else { + if (buffer == null) // initialize buffer for revisits + buffer = new int[TRANSFER_BUFFER_SIZE]; + if (bin < 0 && bufferIndex > 0) { + int j = buffer[--bufferIndex]; + buffer[bufferIndex] = i; + i = j; // swap with another bin + continue; + } + if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { + f.tryAwaitLock(tab, i); + continue; // no other options -- block + } + if (rev == null) // initialize reverse-forwarder + rev = new Node(MOVED, tab, null, null); + if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) + continue; // recheck before adding to list + buffer[nbuffered++] = i; + setTabAt(nextTab, i, rev); // install place-holders + setTabAt(nextTab, i + n, rev); + } + + if (bin > 0) + i = --bin; + else if (buffer != null && nbuffered > 0) { + bin = -1; + i = buffer[bufferIndex = --nbuffered]; + } + else + return nextTab; + } + } + + /** + * Splits a normal bin with list headed by e into lo and hi parts; + * installs in given table. + */ + private static void splitBin(Node[] nextTab, int i, Node e) { + int bit = nextTab.length >>> 1; // bit to split on + int runBit = e.hash & bit; + Node lastRun = e, lo = null, hi = null; + for (Node p = e.next; p != null; p = p.next) { + int b = p.hash & bit; + if (b != runBit) { + runBit = b; + lastRun = p; + } + } + if (runBit == 0) + lo = lastRun; + else + hi = lastRun; + for (Node p = e; p != lastRun; p = p.next) { + int ph = p.hash & HASH_BITS; + Object pk = p.key, pv = p.val; + if ((ph & bit) == 0) + lo = new Node(ph, pk, pv, lo); + else + hi = new Node(ph, pk, pv, hi); + } + setTabAt(nextTab, i, lo); + setTabAt(nextTab, i + bit, hi); + } + + /** + * Splits a tree bin into lo and hi parts; installs in given table. + */ + private static void splitTreeBin(Node[] nextTab, int i, TreeBin t) { + int bit = nextTab.length >>> 1; + TreeBin lt = new TreeBin(); + TreeBin ht = new TreeBin(); + int lc = 0, hc = 0; + for (Node e = t.first; e != null; e = e.next) { + int h = e.hash & HASH_BITS; + Object k = e.key, v = e.val; + if ((h & bit) == 0) { + ++lc; + lt.putTreeNode(h, k, v); + } + else { + ++hc; + ht.putTreeNode(h, k, v); + } + } + Node ln, hn; // throw away trees if too small + if (lc <= (TREE_THRESHOLD >>> 1)) { + ln = null; + for (Node p = lt.first; p != null; p = p.next) + ln = new Node(p.hash, p.key, p.val, ln); + } + else + ln = new Node(MOVED, lt, null, null); + setTabAt(nextTab, i, ln); + if (hc <= (TREE_THRESHOLD >>> 1)) { + hn = null; + for (Node p = ht.first; p != null; p = p.next) + hn = new Node(p.hash, p.key, p.val, hn); + } + else + hn = new Node(MOVED, ht, null, null); + setTabAt(nextTab, i + bit, hn); + } + + /** + * Implementation for clear. Steps through each bin, removing all + * nodes. + */ + private final void internalClear() { + long delta = 0L; // negative number of deletions + int i = 0; + Node[] tab = table; + while (tab != null && i < tab.length) { + int fh; Object fk; + Node f = tabAt(tab, i); + if (f == null) + ++i; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + for (Node p = t.first; p != null; p = p.next) { + if (p.val != null) { // (currently always true) + p.val = null; + --delta; + } + } + t.first = null; + t.root = null; + ++i; + } + } finally { + t.release(0); + } + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); // opportunistically update count + delta = 0L; + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + for (Node e = f; e != null; e = e.next) { + if (e.val != null) { // (currently always true) + e.val = null; + --delta; + } + } + setTabAt(tab, i, null); + ++i; + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + } + } + if (delta != 0) + counter.add(delta); + } + + /* ----------------Table Traversal -------------- */ + + /** + * Encapsulates traversal for methods such as containsValue; also + * serves as a base class for other iterators and bulk tasks. + * + * At each step, the iterator snapshots the key ("nextKey") and + * value ("nextVal") of a valid node (i.e., one that, at point of + * snapshot, has a non-null user value). Because val fields can + * change (including to null, indicating deletion), field nextVal + * might not be accurate at point of use, but still maintains the + * weak consistency property of holding a value that was once + * valid. To support iterator.remove, the nextKey field is not + * updated (nulled out) when the iterator cannot advance. + * + * Internal traversals directly access these fields, as in: + * {@code while (it.advance() != null) { process(it.nextKey); }} + * + * Exported iterators must track whether the iterator has advanced + * (in hasNext vs next) (by setting/checking/nulling field + * nextVal), and then extract key, value, or key-value pairs as + * return values of next(). + * + * The iterator visits once each still-valid node that was + * reachable upon iterator construction. It might miss some that + * were added to a bin after the bin was visited, which is OK wrt + * consistency guarantees. Maintaining this property in the face + * of possible ongoing resizes requires a fair amount of + * bookkeeping state that is difficult to optimize away amidst + * volatile accesses. Even so, traversal maintains reasonable + * throughput. + * + * Normally, iteration proceeds bin-by-bin traversing lists. + * However, if the table has been resized, then all future steps + * must traverse both the bin at the current index as well as at + * (index + baseSize); and so on for further resizings. To + * paranoically cope with potential sharing by users of iterators + * across threads, iteration terminates if a bounds checks fails + * for a table read. + * + * This class extends ForkJoinTask to streamline parallel + * iteration in bulk operations (see BulkTask). This adds only an + * int of space overhead, which is close enough to negligible in + * cases where it is not needed to not worry about it. Because + * ForkJoinTask is Serializable, but iterators need not be, we + * need to add warning suppressions. + */ + @SuppressWarnings("serial") static class Traverser { + final ConcurrentHashMapV8 map; + Node next; // the next entry to use + K nextKey; // cached key field of next + V nextVal; // cached val field of next + Node[] tab; // current table; updated if resized + int index; // index of bin to use next + int baseIndex; // current index of initial table + int baseLimit; // index bound for initial table + int baseSize; // initial table size + + /** Creates iterator for all entries in the table. */ + Traverser(ConcurrentHashMapV8 map) { + this.map = map; + } + + /** Creates iterator for split() methods */ + Traverser(Traverser it) { + ConcurrentHashMapV8 m; Node[] t; + if ((m = this.map = it.map) == null) + t = null; + else if ((t = it.tab) == null && // force parent tab initialization + (t = it.tab = m.table) != null) + it.baseLimit = it.baseSize = t.length; + this.tab = t; + this.baseSize = it.baseSize; + it.baseLimit = this.index = this.baseIndex = + ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; + } + + /** + * Advances next; returns nextVal or null if terminated. + * See above for explanation. + */ + final V advance() { + Node e = next; + V ev = null; + outer: do { + if (e != null) // advance past used/skipped node + e = e.next; + while (e == null) { // get to next non-null bin + ConcurrentHashMapV8 m; + Node[] t; int b, i, n; Object ek; // checks must use locals + if ((t = tab) != null) + n = t.length; + else if ((m = map) != null && (t = tab = m.table) != null) + n = baseLimit = baseSize = t.length; + else + break outer; + if ((b = baseIndex) >= baseLimit || + (i = index) < 0 || i >= n) + break outer; + if ((e = tabAt(t, i)) != null && e.hash == MOVED) { + if ((ek = e.key) instanceof TreeBin) + e = ((TreeBin)ek).first; + else { + tab = (Node[])ek; + continue; // restarts due to null val + } + } // visit upper slots if present + index = (i += baseSize) < n ? i : (baseIndex = b + 1); + } + nextKey = (K) e.key; + } while ((ev = (V) e.val) == null); // skip deleted or special nodes + next = e; + return nextVal = ev; + } + + public final void remove() { + Object k = nextKey; + if (k == null && (advance() == null || (k = nextKey) == null)) + throw new IllegalStateException(); + map.internalReplace(k, null, null); + } + + public final boolean hasNext() { + return nextVal != null || advance() != null; + } + + public final boolean hasMoreElements() { return hasNext(); } + public final void setRawResult(Object x) { } + public R getRawResult() { return null; } + public boolean exec() { return true; } + } + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the default initial table size (16). + */ + public ConcurrentHashMapV8() { + this.counter = new LongAdder(); + } + + /** + * Creates a new, empty map with an initial table size + * accommodating the specified number of elements without the need + * to dynamically resize. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + */ + public ConcurrentHashMapV8(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? + MAXIMUM_CAPACITY : + tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new map with the same mappings as the given map. + * + * @param m the map + */ + public ConcurrentHashMapV8(Map m) { + this.counter = new LongAdder(); + this.sizeCtl = DEFAULT_CAPACITY; + internalPutAll(m); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}) and + * initial table density ({@code loadFactor}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, 1); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}), table + * density ({@code loadFactor}), and number of concurrently + * updating threads ({@code concurrencyLevel}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation may use this value as + * a sizing hint. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive + */ + public ConcurrentHashMapV8(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + if (initialCapacity < concurrencyLevel) // Use at least as many bins + initialCapacity = concurrencyLevel; // as estimated threads + long size = (long)(1.0 + (long)initialCapacity / loadFactor); + int cap = (size >= (long)MAXIMUM_CAPACITY) ? + MAXIMUM_CAPACITY : tableSizeFor((int)size); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @return the new set + */ + public static KeySetView newKeySet() { + return new KeySetView(new ConcurrentHashMapV8(), + Boolean.TRUE); + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + * @return the new set + */ + public static KeySetView newKeySet(int initialCapacity) { + return new KeySetView(new ConcurrentHashMapV8(initialCapacity), + Boolean.TRUE); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return counter.sum() <= 0L; // ignore transient negative values + } + + /** + * {@inheritDoc} + */ + public int size() { + long n = counter.sum(); + return ((n < 0L) ? 0 : + (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : + (int)n); + } + + /** + * Returns the number of mappings. This method should be used + * instead of {@link #size} because a ConcurrentHashMapV8 may + * contain more mappings than can be represented as an int. The + * value returned is a snapshot; the actual count may differ if + * there are ongoing concurrent insertions or removals. + * + * @return the number of mappings + */ + public long mappingCount() { + long n = counter.sum(); + return (n < 0L) ? 0L : n; // ignore transient negative values + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

    More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V get(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalGet(key); + } + + /** + * Returns the value to which the specified key is mapped, + * or the given defaultValue if this map contains no mapping for the key. + * + * @param key the key + * @param defaultValue the value to return if this map contains + * no mapping for the given key + * @return the mapping for the key, if present; else the defaultValue + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { + if (key == null) + throw new NullPointerException(); + V v = (V) internalGet(key); + return v == null ? defaultValue : v; + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return {@code true} if and only if the specified object + * is a key in this table, as determined by the + * {@code equals} method; {@code false} otherwise + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + if (key == null) + throw new NullPointerException(); + return internalGet(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. Note: This method may require a full traversal + * of the map, and is much slower than method {@code containsKey}. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return true; + } + return false; + } + + public K findKey(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return it.nextKey; + } + return null; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + * + * @param value a value to search for + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this table as + * determined by the {@code equals} method; + * {@code false} otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + *

    The value can be retrieved by calling the {@code get} method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPut(key, value); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPutIfAbsent(key, value); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map m) { + internalPutAll(m); + } + + /** + * If the specified key is not already associated with a value, + * computes its value using the given mappingFunction and enters + * it into the map unless null. This is equivalent to + *

     {@code
    +     * if (map.containsKey(key))
    +     *   return map.get(key);
    +     * value = mappingFunction.apply(key);
    +     * if (value != null)
    +     *   map.put(key, value);
    +     * return value;}
    + * + * except that the action is performed atomically. If the + * function returns {@code null} no mapping is recorded. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and no mapping is recorded. Some + * attempted update operations on this map by other threads may be + * blocked while computation is in progress, so the computation + * should be short and simple, and must not attempt to update any + * other mappings of this Map. The most appropriate usage is to + * construct a new object serving as an initial mapped value, or + * memoized result, as in: + * + *
     {@code
    +     * map.computeIfAbsent(key, new Fun() {
    +     *   public V map(K k) { return new Value(f(k)); }});}
    + * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key or mappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, + * in which case the mapping is left unestablished + */ + @SuppressWarnings("unchecked") public V computeIfAbsent + (K key, Fun mappingFunction) { + if (key == null || mappingFunction == null) + throw new NullPointerException(); + return (V)internalComputeIfAbsent(key, mappingFunction); + } + + /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
     {@code
    +     *   if (map.containsKey(key)) {
    +     *     value = remappingFunction.apply(key, map.get(key));
    +     *     if (value != null)
    +     *       map.put(key, value);
    +     *     else
    +     *       map.remove(key);
    +     *   }
    +     * }
    + * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V computeIfPresent + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** + * Computes a new mapping value given a key and + * its current mapped value (or {@code null} if there is no current + * mapping). This is equivalent to + *
     {@code
    +     *   value = remappingFunction.apply(key, map.get(key));
    +     *   if (value != null)
    +     *     map.put(key, value);
    +     *   else
    +     *     map.remove(key);
    +     * }
    + * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + *
     {@code
    +     * Map map = ...;
    +     * final String msg = ...;
    +     * map.compute(key, new BiFun() {
    +     *   public String apply(Key k, String v) {
    +     *    return (v == null) ? msg : v + msg;});}}
    + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V compute + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
     {@code
    +     *   if (!map.containsKey(key))
    +     *     map.put(value);
    +     *   else {
    +     *     newValue = remappingFunction.apply(map.get(key), value);
    +     *     if (value != null)
    +     *       map.put(key, value);
    +     *     else
    +     *       map.remove(key);
    +     *   }
    +     * }
    + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + @SuppressWarnings("unchecked") public V merge + (K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V remove(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalReplace(key, null, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return internalReplace(key, null, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (key == null || oldValue == null || newValue == null) + throw new NullPointerException(); + return internalReplace(key, newValue, oldValue) != null; + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V replace(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalReplace(key, value, null); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + internalClear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. + * + * @return the set view + */ + public KeySetView keySet() { + KeySetView ks = keySet; + return (ks != null) ? ks : (keySet = new KeySetView(this, null)); + } + + /** + * Returns a {@link Set} view of the keys in this map, using the + * given common mapped value for any additions (i.e., {@link + * Collection#add} and {@link Collection#addAll}). This is of + * course only appropriate if it is acceptable to use the same + * value for all additions from this view. + * + * @param mappedValue the mapped value to use for any + * additions. + * @return the set view + * @throws NullPointerException if the mappedValue is null + */ + public KeySetView keySet(V mappedValue) { + if (mappedValue == null) + throw new NullPointerException(); + return new KeySetView(this, mappedValue); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. + */ + public ValuesView values() { + ValuesView vs = values; + return (vs != null) ? vs : (values = new ValuesView(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. + * + *

    The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set> entrySet() { + EntrySetView es = entrySet; + return (es != null) ? es : (entrySet = new EntrySetView(this)); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet() + */ + public Enumeration keys() { + return new KeyIterator(this); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values() + */ + public Enumeration elements() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the keys in this map. + * + * @return a partitionable iterator of the keys in this map + */ + public Spliterator keySpliterator() { + return new KeyIterator(this); + } + + /** + * Returns a partitionable iterator of the values in this map. + * + * @return a partitionable iterator of the values in this map + */ + public Spliterator valueSpliterator() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the entries in this map. + * + * @return a partitionable iterator of the entries in this map + */ + public Spliterator> entrySpliterator() { + return new EntryIterator(this); + } + + /** + * Returns the hash code value for this {@link Map}, i.e., + * the sum of, for each key-value pair in the map, + * {@code key.hashCode() ^ value.hashCode()}. + * + * @return the hash code value for this map + */ + public int hashCode() { + int h = 0; + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + h += it.nextKey.hashCode() ^ v.hashCode(); + } + return h; + } + + /** + * Returns a string representation of this map. The string + * representation consists of a list of key-value mappings (in no + * particular order) enclosed in braces ("{@code {}}"). Adjacent + * mappings are separated by the characters {@code ", "} (comma + * and space). Each key-value mapping is rendered as the key + * followed by an equals sign ("{@code =}") followed by the + * associated value. + * + * @return a string representation of this map + */ + public String toString() { + Traverser it = new Traverser(this); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + Object v; + if ((v = it.advance()) != null) { + for (;;) { + Object k = it.nextKey; + sb.append(k == this ? "(this Map)" : k); + sb.append('='); + sb.append(v == this ? "(this Map)" : v); + if ((v = it.advance()) == null) + break; + sb.append(',').append(' '); + } + } + return sb.append('}').toString(); + } + + /** + * Compares the specified object with this map for equality. + * Returns {@code true} if the given object is a map with the same + * mappings as this map. This operation may return misleading + * results if either map is concurrently modified during execution + * of this method. + * + * @param o object to be compared for equality with this map + * @return {@code true} if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o != this) { + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + Traverser it = new Traverser(this); + Object val; + while ((val = it.advance()) != null) { + Object v = m.get(it.nextKey); + if (v == null || (v != val && !v.equals(val))) + return false; + } + for (Map.Entry e : m.entrySet()) { + Object mk, mv, v; + if ((mk = e.getKey()) == null || + (mv = e.getValue()) == null || + (v = internalGet(mk)) == null || + (mv != v && !mv.equals(v))) + return false; + } + } + return true; + } + + /* ----------------Iterators -------------- */ + + @SuppressWarnings("serial") static final class KeyIterator extends Traverser + implements Spliterator, Enumeration { + KeyIterator(ConcurrentHashMapV8 map) { super(map); } + KeyIterator(Traverser it) { + super(it); + } + public KeyIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new KeyIterator(this); + } + @SuppressWarnings("unchecked") public final K next() { + if (nextVal == null && advance() == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return (K) k; + } + + public final K nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class ValueIterator extends Traverser + implements Spliterator, Enumeration { + ValueIterator(ConcurrentHashMapV8 map) { super(map); } + ValueIterator(Traverser it) { + super(it); + } + public ValueIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new ValueIterator(this); + } + + @SuppressWarnings("unchecked") public final V next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + nextVal = null; + return (V) v; + } + + public final V nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class EntryIterator extends Traverser + implements Spliterator> { + EntryIterator(ConcurrentHashMapV8 map) { super(map); } + EntryIterator(Traverser it) { + super(it); + } + public EntryIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new EntryIterator(this); + } + + @SuppressWarnings("unchecked") public final Map.Entry next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return new MapEntry((K)k, (V)v, map); + } + } + + /** + * Exported Entry for iterators + */ + static final class MapEntry implements Map.Entry { + final K key; // non-null + V val; // non-null + final ConcurrentHashMapV8 map; + MapEntry(K key, V val, ConcurrentHashMapV8 map) { + this.key = key; + this.val = val; + this.map = map; + } + public final K getKey() { return key; } + public final V getValue() { return val; } + public final int hashCode() { return key.hashCode() ^ val.hashCode(); } + public final String toString(){ return key + "=" + val; } + + public final boolean equals(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + (k == key || k.equals(key)) && + (v == val || v.equals(val))); + } + + /** + * Sets our entry's value and writes through to the map. The + * value to return is somewhat arbitrary here. Since we do not + * necessarily track asynchronous changes, the most recent + * "previous" value could be different from what we return (or + * could even have been removed in which case the put will + * re-establish). We do not and cannot guarantee more. + */ + public final V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = val; + val = value; + map.put(key, value); + return v; + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Stripped-down version of helper class used in previous version, + * declared for the sake of serialization compatibility + */ + static class Segment implements Serializable { + private static final long serialVersionUID = 2249069246763182397L; + final float loadFactor; + Segment(float lf) { this.loadFactor = lf; } + } + + /** + * Saves the state of the {@code ConcurrentHashMapV8} instance to a + * stream (i.e., serializes it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + if (segments == null) { // for serialization compatibility + segments = (Segment[]) + new Segment[DEFAULT_CONCURRENCY_LEVEL]; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(LOAD_FACTOR); + } + s.defaultWriteObject(); + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + s.writeObject(it.nextKey); + s.writeObject(v); + } + s.writeObject(null); + s.writeObject(null); + segments = null; // throw away + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + this.segments = null; // unneeded + // initialize transient final field + UNSAFE.putObjectVolatile(this, counterOffset, new LongAdder()); + + // Create all nodes, then place in table once size is known + long size = 0L; + Node p = null; + for (;;) { + K k = (K) s.readObject(); + V v = (V) s.readObject(); + if (k != null && v != null) { + int h = spread(k.hashCode()); + p = new Node(h, k, v, p); + ++size; + } + else + break; + } + if (p != null) { + boolean init = false; + int n; + if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) + n = MAXIMUM_CAPACITY; + else { + int sz = (int)size; + n = tableSizeFor(sz + (sz >>> 1) + 1); + } + int sc = sizeCtl; + boolean collide = false; + if (n > sc && + UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == null) { + init = true; + Node[] tab = new Node[n]; + int mask = n - 1; + while (p != null) { + int j = p.hash & mask; + Node next = p.next; + Node q = p.next = tabAt(tab, j); + setTabAt(tab, j, p); + if (!collide && q != null && q.hash == p.hash) + collide = true; + p = next; + } + table = tab; + counter.add(size); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + if (collide) { // rescan and convert to TreeBins + Node[] tab = table; + for (int i = 0; i < tab.length; ++i) { + int c = 0; + for (Node e = tabAt(tab, i); e != null; e = e.next) { + if (++c > TREE_THRESHOLD && + (e.key instanceof Comparable)) { + replaceWithTreeBin(tab, i, e.key); + break; + } + } + } + } + } + if (!init) { // Can only happen if unsafely published. + while (p != null) { + internalPut(p.key, p.val); + p = p.next; + } + } + } + } + + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + /* ----------------Views -------------- */ + + /** + * Base class for views. + */ + static abstract class CHMView { + final ConcurrentHashMapV8 map; + CHMView(ConcurrentHashMapV8 map) { this.map = map; } + + /** + * Returns the map backing this view. + * + * @return the map backing this view + */ + public ConcurrentHashMapV8 getMap() { return map; } + + public final int size() { return map.size(); } + public final boolean isEmpty() { return map.isEmpty(); } + public final void clear() { map.clear(); } + + // implementations below rely on concrete classes supplying these + abstract public Iterator iterator(); + abstract public boolean contains(Object o); + abstract public boolean remove(Object o); + + private static final String oomeMsg = "Required array size too large"; + + public final Object[] toArray() { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int n = (int)sz; + Object[] r = new Object[n]; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = it.next(); + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int m = (int)sz; + T[] r = (a.length >= m) ? a : + (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), m); + int n = r.length; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = (T)it.next(); + } + if (a == r && i < n) { + r[i] = null; // null-terminate + return r; + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + public final int hashCode() { + int h = 0; + for (Iterator it = iterator(); it.hasNext();) + h += it.next().hashCode(); + return h; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + Iterator it = iterator(); + if (it.hasNext()) { + for (;;) { + Object e = it.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!it.hasNext()) + break; + sb.append(',').append(' '); + } + } + return sb.append(']').toString(); + } + + public final boolean containsAll(Collection c) { + if (c != this) { + for (Iterator it = c.iterator(); it.hasNext();) { + Object e = it.next(); + if (e == null || !contains(e)) + return false; + } + } + return true; + } + + public final boolean removeAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + public final boolean retainAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (!c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in + * which additions may optionally be enabled by mapping to a + * common value. This class cannot be directly instantiated. See + * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, + * {@link #newKeySet(int)}. + */ + public static class KeySetView extends CHMView implements Set, java.io.Serializable { + private static final long serialVersionUID = 7249069246763182397L; + private final V value; + KeySetView(ConcurrentHashMapV8 map, V value) { // non-public + super(map); + this.value = value; + } + + /** + * Returns the default mapped value for additions, + * or {@code null} if additions are not supported. + * + * @return the default mapped value for additions, or {@code null} + * if not supported. + */ + public V getMappedValue() { return value; } + + // implement Set API + + public boolean contains(Object o) { return map.containsKey(o); } + public boolean remove(Object o) { return map.remove(o) != null; } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the keys of this map + */ + public Iterator iterator() { return new KeyIterator(map); } + public boolean add(K e) { + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + if (e == null) + throw new NullPointerException(); + return map.internalPutIfAbsent(e, v) == null; + } + public boolean addAll(Collection c) { + boolean added = false; + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + for (K e : c) { + if (e == null) + throw new NullPointerException(); + if (map.internalPutIfAbsent(e, v) == null) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Collection} of + * values, in which additions are disabled. This class cannot be + * directly instantiated. See {@link #values}, + * + *

    The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public static final class ValuesView extends CHMView + implements Collection { + ValuesView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { return map.containsValue(o); } + public final boolean remove(Object o) { + if (o != null) { + Iterator it = new ValueIterator(map); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + } + return false; + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the values of this map + */ + public final Iterator iterator() { + return new ValueIterator(map); + } + public final boolean add(V e) { + throw new UnsupportedOperationException(); + } + public final boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) + * entries. This class cannot be directly instantiated. See + * {@link #entrySet}. + */ + public static final class EntrySetView extends CHMView + implements Set> { + EntrySetView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { + Object k, v, r; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (r = map.get(k)) != null && + (v = e.getValue()) != null && + (v == r || v.equals(r))); + } + public final boolean remove(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + map.remove(k, v)); + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the entries of this map + */ + public final Iterator> iterator() { + return new EntryIterator(map); + } + + public final boolean add(Entry e) { + K key = e.getKey(); + V value = e.getValue(); + if (key == null || value == null) + throw new NullPointerException(); + return map.internalPut(key, value) == null; + } + public final boolean addAll(Collection> c) { + boolean added = false; + for (Entry e : c) { + if (add(e)) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long counterOffset; + private static final long sizeCtlOffset; + private static final long ABASE; + private static final int ASHIFT; + + static { + int ss; + try { + UNSAFE = getUnsafe(); + Class k = ConcurrentHashMapV8.class; + counterOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("counter")); + sizeCtlOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("sizeCtl")); + Class sc = Node[].class; + ABASE = UNSAFE.arrayBaseOffset(sc); + ss = UNSAFE.arrayIndexScale(sc); + } catch (Exception e) { + throw new Error(e); + } + if ((ss & (ss-1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(ss); + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + return java.security.AccessController.doPrivileged + (new java.security + .PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + java.lang.reflect.Field f = sun.misc + .Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } + } +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/LongAdder.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/LongAdder.java new file mode 100644 index 0000000..22d0cbc --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/LongAdder.java @@ -0,0 +1,203 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.9 version. + +package org.jruby.ext.thread_safe.jsr166e; +import java.util.concurrent.atomic.AtomicLong; +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

    This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

    This class extends {@link Number}, but does not define + * methods such as {@code hashCode} and {@code compareTo} because + * instances are expected to be mutated, and so are not useful as + * collection keys. + * + *

    jsr166e note: This class is targeted to be placed in + * java.util.concurrent.atomic. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Version of plus for use in retryUpdate + */ + final long fn(long v, long x) { return v + x; } + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; HashCode hc; Cell a; int n; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + int h = (hc = threadHashCode.get()).code; + if (as == null || (n = as.length) < 1 || + (a = as[(n - 1) & h]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + retryUpdate(x, hc, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot: Invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + long sum = base; + Cell[] as = cells; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + internalReset(0L); + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + long sum = base; + Cell[] as = cells; + base = 0L; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + busy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/Striped64.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/Striped64.java new file mode 100644 index 0000000..8651cdc --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/Striped64.java @@ -0,0 +1,342 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.5 version. + +package org.jruby.ext.thread_safe.jsr166e; +import java.util.Random; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("busy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock: When the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * Per-thread hash codes are initialized to random values. + * Contention and/or table collisions are indicated by failed + * CASes when performing an update operation (see method + * retryUpdate). Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long valueOffset; + static { + try { + UNSAFE = getUnsafe(); + Class ak = Cell.class; + valueOffset = UNSAFE.objectFieldOffset + (ak.getDeclaredField("value")); + } catch (Exception e) { + throw new Error(e); + } + } + + } + + /** + * Holder for the thread-local hash code. The code is initially + * random, but may be set to a different value upon collisions. + */ + static final class HashCode { + static final Random rng = new Random(); + int code; + HashCode() { + int h = rng.nextInt(); // Avoid zero to allow xorShift rehash + code = (h == 0) ? 1 : h; + } + } + + /** + * The corresponding ThreadLocal class + */ + static final class ThreadHashCode extends ThreadLocal { + public HashCode initialValue() { return new HashCode(); } + } + + /** + * Static per-thread hash codes. Shared across all instances to + * reduce ThreadLocal pollution and because adjustments due to + * collisions in one table are likely to be appropriate for + * others. + */ + static final ThreadHashCode threadHashCode = new ThreadHashCode(); + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int busy; + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); + } + + /** + * CASes the busy field from 0 to 1 to acquire lock. + */ + final boolean casBusy() { + return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); + } + + /** + * Computes the function of current and new value. Subclasses + * should open-code this update function for most uses, but the + * virtualized form is needed within retryUpdate. + * + * @param currentValue the current value (of either base or a cell) + * @param newValue the argument from a user update call + * @return result of the update function + */ + abstract long fn(long currentValue, long newValue); + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param hc the hash code holder + * @param wasUncontended false if CAS failed before call + */ + final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { + int h = hc.code; + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (busy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (busy == 0 && casBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + busy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, fn(v, x))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (busy == 0 && casBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + busy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h ^= h << 13; // Rehash + h ^= h >>> 17; + h ^= h << 5; + } + else if (busy == 0 && cells == as && casBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + busy = 0; + } + if (init) + break; + } + else if (casBase(v = base, fn(v, x))) + break; // Fall back on using base + } + hc.code = h; // Record index for next time + } + + + /** + * Sets base and all cells to the given value. + */ + final void internalReset(long initialValue) { + Cell[] as = cells; + base = initialValue; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + a.value = initialValue; + } + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long baseOffset; + private static final long busyOffset; + static { + try { + UNSAFE = getUnsafe(); + Class sk = Striped64.class; + baseOffset = UNSAFE.objectFieldOffset + (sk.getDeclaredField("base")); + busyOffset = UNSAFE.objectFieldOffset + (sk.getDeclaredField("busy")); + } catch (Exception e) { + throw new Error(e); + } + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + return java.security.AccessController.doPrivileged + (new java.security + .PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + java.lang.reflect.Field f = sun.misc + .Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } + } + +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java new file mode 100644 index 0000000..4e1e33a --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java @@ -0,0 +1,3800 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on the 1.79 version. + +package org.jruby.ext.thread_safe.jsr166e.nounsafe; + +import org.jruby.RubyClass; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.exceptions.RaiseException; +import org.jruby.ext.thread_safe.jsr166e.ConcurrentHashMap; +import org.jruby.ext.thread_safe.jsr166y.ThreadLocalRandom; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +import java.io.Serializable; + +/** + * A hash table supporting full concurrency of retrievals and + * high expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * {@code Hashtable}. However, even though all operations are + * thread-safe, retrieval operations do not entail locking, + * and there is not any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with {@code Hashtable} in programs that rely on its + * thread safety but not on its synchronization details. + * + *

    Retrieval operations (including {@code get}) generally do not + * block, so may overlap with update operations (including {@code put} + * and {@code remove}). Retrievals reflect the results of the most + * recently completed update operations holding upon their + * onset. (More formally, an update operation for a given key bears a + * happens-before relation with any (non-null) retrieval for + * that key reporting the updated value.) For aggregate operations + * such as {@code putAll} and {@code clear}, concurrent retrievals may + * reflect insertion or removal of only some entries. Similarly, + * Iterators and Enumerations return elements reflecting the state of + * the hash table at some point at or since the creation of the + * iterator/enumeration. They do not throw {@link + * ConcurrentModificationException}. However, iterators are designed + * to be used by only one thread at a time. Bear in mind that the + * results of aggregate status methods including {@code size}, {@code + * isEmpty}, and {@code containsValue} are typically useful only when + * a map is not undergoing concurrent updates in other threads. + * Otherwise the results of these methods reflect transient states + * that may be adequate for monitoring or estimation purposes, but not + * for program control. + * + *

    The table is dynamically expanded when there are too many + * collisions (i.e., keys that have distinct hash codes but fall into + * the same slot modulo the table size), with the expected average + * effect of maintaining roughly two bins per mapping (corresponding + * to a 0.75 load factor threshold for resizing). There may be much + * variance around this average as mappings are added and removed, but + * overall, this maintains a commonly accepted time/space tradeoff for + * hash tables. However, resizing this or any other kind of hash + * table may be a relatively slow operation. When possible, it is a + * good idea to provide a size estimate as an optional {@code + * initialCapacity} constructor argument. An additional optional + * {@code loadFactor} constructor argument provides a further means of + * customizing initial table capacity by specifying the table density + * to be used in calculating the amount of space to allocate for the + * given number of elements. Also, for compatibility with previous + * versions of this class, constructors may optionally specify an + * expected {@code concurrencyLevel} as an additional hint for + * internal sizing. Note that using many keys with exactly the same + * {@code hashCode()} is a sure way to slow down performance of any + * hash table. + * + *

    A {@link Set} projection of a ConcurrentHashMapV8 may be created + * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed + * (using {@link #keySet(Object)} when only keys are of interest, and the + * mapped values are (perhaps transiently) not used or all take the + * same mapping value. + * + *

    A ConcurrentHashMapV8 can be used as scalable frequency map (a + * form of histogram or multiset) by using {@link LongAdder} values + * and initializing via {@link #computeIfAbsent}. For example, to add + * a count to a {@code ConcurrentHashMapV8 freqs}, you + * can use {@code freqs.computeIfAbsent(k -> new + * LongAdder()).increment();} + * + *

    This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. + * + *

    Like {@link Hashtable} but unlike {@link HashMap}, this class + * does not allow {@code null} to be used as a key or value. + * + *

    ConcurrentHashMapV8s support parallel operations using the {@link + * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts + * are available in class {@link ForkJoinTasks}). These operations are + * designed to be safely, and often sensibly, applied even with maps + * that are being concurrently updated by other threads; for example, + * when computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and (Key, + * Value) arguments and/or return values. (The first three forms are + * also available via the {@link #keySet()}, {@link #values()} and + * {@link #entrySet()} views). Because the elements of a + * ConcurrentHashMapV8 are not ordered in any particular way, and may be + * processed in different orders in different parallel executions, the + * correctness of supplied functions should not depend on any + * ordering, or on any other objects or values that may transiently + * change while computation is in progress; and except for forEach + * actions, should ideally be side-effect-free. + * + *

    + * + *

    The concurrency properties of bulk operations follow + * from those of ConcurrentHashMapV8: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

    Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

    Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

    Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

    Parallel speedups for bulk operations compared to sequential + * processing are common but not guaranteed. Operations involving + * brief functions on small maps may execute more slowly than + * sequential loops if the underlying work to parallelize the + * computation is more expensive than the computation itself. + * Similarly, parallelization may not lead to much actual parallelism + * if all processors are busy performing unrelated tasks. + * + *

    All arguments to all task methods must be non-null. + * + *

    jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + * + *

    This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +public class ConcurrentHashMapV8 + implements ConcurrentMap, Serializable, ConcurrentHashMap { + private static final long serialVersionUID = 7249069246763182397L; + + /** + * A partitionable iterator. A Spliterator can be traversed + * directly, but can also be partitioned (before traversal) by + * creating another Spliterator that covers a non-overlapping + * portion of the elements, and so may be amenable to parallel + * execution. + * + *

    This interface exports a subset of expected JDK8 + * functionality. + * + *

    Sample usage: Here is one (of the several) ways to compute + * the sum of the values held in a map using the ForkJoin + * framework. As illustrated here, Spliterators are well suited to + * designs in which a task repeatedly splits off half its work + * into forked subtasks until small enough to process directly, + * and then joins these subtasks. Variants of this style can also + * be used in completion-based designs. + * + *

    +     * {@code ConcurrentHashMapV8 m = ...
    +     * // split as if have 8 * parallelism, for load balance
    +     * int n = m.size();
    +     * int p = aForkJoinPool.getParallelism() * 8;
    +     * int split = (n < p)? n : p;
    +     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
    +     * // ...
    +     * static class SumValues extends RecursiveTask {
    +     *   final Spliterator s;
    +     *   final int split;             // split while > 1
    +     *   final SumValues nextJoin;    // records forked subtasks to join
    +     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
    +     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
    +     *   }
    +     *   public Long compute() {
    +     *     long sum = 0;
    +     *     SumValues subtasks = null; // fork subtasks
    +     *     for (int s = split >>> 1; s > 0; s >>>= 1)
    +     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
    +     *     while (s.hasNext())        // directly process remaining elements
    +     *       sum += s.next();
    +     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
    +     *       sum += t.join();         // collect subtask results
    +     *     return sum;
    +     *   }
    +     * }
    +     * }
    + */ + public static interface Spliterator extends Iterator { + /** + * Returns a Spliterator covering approximately half of the + * elements, guaranteed not to overlap with those subsequently + * returned by this Spliterator. After invoking this method, + * the current Spliterator will not produce any of + * the elements of the returned Spliterator, but the two + * Spliterators together will produce all of the elements that + * would have been produced by this Spliterator had this + * method not been called. The exact number of elements + * produced by the returned Spliterator is not guaranteed, and + * may be zero (i.e., with {@code hasNext()} reporting {@code + * false}) if this Spliterator cannot be further split. + * + * @return a Spliterator covering approximately half of the + * elements + * @throws IllegalStateException if this Spliterator has + * already commenced traversing elements + */ + Spliterator split(); + } + + + /* + * Overview: + * + * The primary design goal of this hash table is to maintain + * concurrent readability (typically method get(), but also + * iterators and related methods) while minimizing update + * contention. Secondary goals are to keep space consumption about + * the same or better than java.util.HashMap, and to support high + * initial insertion rates on an empty table by many threads. + * + * Each key-value mapping is held in a Node. Because Node fields + * can contain special values, they are defined using plain Object + * types. Similarly in turn, all internal methods that use them + * work off Object types. And similarly, so do the internal + * methods of auxiliary iterator and view classes. All public + * generic typed methods relay in/out of these internal methods, + * supplying null-checks and casts as needed. This also allows + * many of the public methods to be factored into a smaller number + * of internal methods (although sadly not so for the five + * variants of put-related operations). The validation-based + * approach explained below leads to a lot of code sprawl because + * retry-control precludes factoring into smaller methods. + * + * The table is lazily initialized to a power-of-two size upon the + * first insertion. Each bin in the table normally contains a + * list of Nodes (most often, the list has only zero or one Node). + * Table accesses require volatile/atomic reads, writes, and + * CASes. Because there is no other way to arrange this without + * adding further indirections, we use intrinsics + * (sun.misc.Unsafe) operations. The lists of nodes within bins + * are always accurately traversable under volatile reads, so long + * as lookups check hash code and non-nullness of value before + * checking key equality. + * + * We use the top two bits of Node hash fields for control + * purposes -- they are available anyway because of addressing + * constraints. As explained further below, these top bits are + * used as follows: + * 00 - Normal + * 01 - Locked + * 11 - Locked and may have a thread waiting for lock + * 10 - Node is a forwarding node + * + * The lower 30 bits of each Node's hash field contain a + * transformation of the key's hash code, except for forwarding + * nodes, for which the lower bits are zero (and so always have + * hash field == MOVED). + * + * Insertion (via put or its variants) of the first node in an + * empty bin is performed by just CASing it to the bin. This is + * by far the most common case for put operations under most + * key/hash distributions. Other update operations (insert, + * delete, and replace) require locks. We do not want to waste + * the space required to associate a distinct lock object with + * each bin, so instead use the first node of a bin list itself as + * a lock. Blocking support for these locks relies on the builtin + * "synchronized" monitors. However, we also need a tryLock + * construction, so we overlay these by using bits of the Node + * hash field for lock control (see above), and so normally use + * builtin monitors only for blocking and signalling using + * wait/notifyAll constructions. See Node.tryAwaitLock. + * + * Using the first node of a list as a lock does not by itself + * suffice though: When a node is locked, any update must first + * validate that it is still the first node after locking it, and + * retry if not. Because new nodes are always appended to lists, + * once a node is first in a bin, it remains first until deleted + * or the bin becomes invalidated (upon resizing). However, + * operations that only conditionally update may inspect nodes + * until the point of update. This is a converse of sorts to the + * lazy locking technique described by Herlihy & Shavit. + * + * The main disadvantage of per-bin locks is that other update + * operations on other nodes in a bin list protected by the same + * lock can stall, for example when user equals() or mapping + * functions take a long time. However, statistically, under + * random hash codes, this is not a common problem. Ideally, the + * frequency of nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average, given the resizing threshold + * of 0.75, although with a large variance because of resizing + * granularity. Ignoring variance, the expected occurrences of + * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + * first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * Lock contention probability for two threads accessing distinct + * elements is roughly 1 / (8 * #elements) under random hashes. + * + * Actual hash code distributions encountered in practice + * sometimes deviate significantly from uniform randomness. This + * includes the case when N > (1<<30), so some keys MUST collide. + * Similarly for dumb or hostile usages in which multiple keys are + * designed to have identical hash codes. Also, although we guard + * against the worst effects of this (see method spread), sets of + * hashes may differ only in bits that do not impact their bin + * index for a given power-of-two mask. So we use a secondary + * strategy that applies when the number of nodes in a bin exceeds + * a threshold, and at least one of the keys implements + * Comparable. These TreeBins use a balanced tree to hold nodes + * (a specialized form of red-black trees), bounding search time + * to O(log N). Each search step in a TreeBin is around twice as + * slow as in a regular list, but given that N cannot exceed + * (1<<64) (before running out of addresses) this bounds search + * steps, lock hold times, etc, to reasonable constants (roughly + * 100 nodes inspected per operation worst case) so long as keys + * are Comparable (which is very common -- String, Long, etc). + * TreeBin nodes (TreeNodes) also maintain the same "next" + * traversal pointers as regular nodes, so can be traversed in + * iterators in the same way. + * + * The table is resized when occupancy exceeds a percentage + * threshold (nominally, 0.75, but see below). Only a single + * thread performs the resize (using field "sizeCtl", to arrange + * exclusion), but the table otherwise remains usable for reads + * and updates. Resizing proceeds by transferring bins, one by + * one, from the table to the next table. Because we are using + * power-of-two expansion, the elements from each bin must either + * stay at same index, or move with a power of two offset. We + * eliminate unnecessary node creation by catching cases where old + * nodes can be reused because their next fields won't change. On + * average, only about one-sixth of them need cloning when a table + * doubles. The nodes they replace will be garbage collectable as + * soon as they are no longer referenced by any reader thread that + * may be in the midst of concurrently traversing table. Upon + * transfer, the old table bin contains only a special forwarding + * node (with hash field "MOVED") that contains the next table as + * its key. On encountering a forwarding node, access and update + * operations restart, using the new table. + * + * Each bin transfer requires its bin lock. However, unlike other + * cases, a transfer can skip a bin if it fails to acquire its + * lock, and revisit it later (unless it is a TreeBin). Method + * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that + * have been skipped because of failure to acquire a lock, and + * blocks only if none are available (i.e., only very rarely). + * The transfer operation must also ensure that all accessible + * bins in both the old and new table are usable by any traversal. + * When there are no lock acquisition failures, this is arranged + * simply by proceeding from the last bin (table.length - 1) up + * towards the first. Upon seeing a forwarding node, traversals + * (see class Iter) arrange to move to the new table + * without revisiting nodes. However, when any node is skipped + * during a transfer, all earlier table bins may have become + * visible, so are initialized with a reverse-forwarding node back + * to the old table until the new ones are established. (This + * sometimes requires transiently locking a forwarding node, which + * is possible under the above encoding.) These more expensive + * mechanics trigger only when necessary. + * + * The traversal scheme also applies to partial traversals of + * ranges of bins (via an alternate Traverser constructor) + * to support partitioned aggregate operations. Also, read-only + * operations give up if ever forwarded to a null table, which + * provides support for shutdown-style clearing, which is also not + * currently implemented. + * + * Lazy table initialization minimizes footprint until first use, + * and also avoids resizings when the first operation is from a + * putAll, constructor with map argument, or deserialization. + * These cases attempt to override the initial capacity settings, + * but harmlessly fail to take effect in cases of races. + * + * The element count is maintained using a LongAdder, which avoids + * contention on updates but can encounter cache thrashing if read + * too frequently during concurrent access. To avoid reading so + * often, resizing is attempted either when a bin lock is + * contended, or upon adding to a bin already holding two or more + * nodes (checked before adding in the xIfAbsent methods, after + * adding in others). Under uniform hash distributions, the + * probability of this occurring at threshold is around 13%, + * meaning that only about 1 in 8 puts check threshold (and after + * resizing, many fewer do so). But this approximation has high + * variance for small table sizes, so we check on any collision + * for sizes <= 64. The bulk putAll operation further reduces + * contention by only committing count updates upon these size + * checks. + * + * Maintaining API and serialization compatibility with previous + * versions of this class introduces several oddities. Mainly: We + * leave untouched but unused constructor arguments refering to + * concurrencyLevel. We accept a loadFactor constructor argument, + * but apply it only to initial table capacity (which is the only + * time that we can guarantee to honor it.) We also declare an + * unused "Segment" class that is instantiated in minimal form + * only when serializing. + */ + + /* ---------------- Constants -------------- */ + + /** + * The largest possible table capacity. This value must be + * exactly 1<<30 to stay within Java array allocation and indexing + * bounds for power of two table sizes, and is further required + * because the top two bits of 32bit hash fields are used for + * control purposes. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default initial table capacity. Must be a power of 2 + * (i.e., at least 1) and at most MAXIMUM_CAPACITY. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The largest possible (non-power of two) array size. + * Needed by toArray and related methods. + */ + static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * The default concurrency level for this table. Unused but + * defined for compatibility with previous versions of this class. + */ + private static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The load factor for this table. Overrides of this value in + * constructors affect only the initial table capacity. The + * actual floating point value isn't normally used -- it is + * simpler to use expressions such as {@code n - (n >>> 2)} for + * the associated resizing threshold. + */ + private static final float LOAD_FACTOR = 0.75f; + + /** + * The buffer size for skipped bins during transfers. The + * value is arbitrary but should be large enough to avoid + * most locking stalls during resizes. + */ + private static final int TRANSFER_BUFFER_SIZE = 32; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. The value reflects the approximate break-even point for + * using tree-based operations. + * Note that Doug's version defaults to 8, but when dealing with + * Ruby objects it is actually beneficial to avoid TreeNodes + * as long as possible as it usually means going into Ruby land. + */ + private static final int TREE_THRESHOLD = 16; + + /* + * Encodings for special uses of Node hash fields. See above for + * explanation. + */ + static final int MOVED = 0x80000000; // hash field for forwarding nodes + static final int LOCKED = 0x40000000; // set/tested only as a bit + static final int WAITING = 0xc0000000; // both bits set/tested together + static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash + + /* ---------------- Fields -------------- */ + + /** + * The array of bins. Lazily initialized upon first insertion. + * Size is always a power of two. Accessed directly by iterators. + */ + transient volatile AtomicReferenceArray table; + + /** + * The counter maintaining number of elements. + */ + private transient LongAdder counter; + + /** + * Table initialization and resizing control. When negative, the + * table is being initialized or resized. Otherwise, when table is + * null, holds the initial table size to use upon creation, or 0 + * for default. After initialization, holds the next element count + * value upon which to resize the table. + */ + private transient volatile int sizeCtl; + + // views + private transient KeySetView keySet; + private transient ValuesView values; + private transient EntrySetView entrySet; + + /** For serialization compatibility. Null unless serialized; see below */ + private Segment[] segments; + + static AtomicIntegerFieldUpdater SIZE_CTRL_UPDATER = AtomicIntegerFieldUpdater.newUpdater(ConcurrentHashMapV8.class, "sizeCtl"); + + /* ---------------- Table element access -------------- */ + + /* + * Volatile access methods are used for table elements as well as + * elements of in-progress next table while resizing. Uses are + * null checked by callers, and implicitly bounds-checked, relying + * on the invariants that tab arrays have non-zero size, and all + * indices are masked with (tab.length - 1) which is never + * negative and always less than length. Note that, to be correct + * wrt arbitrary concurrency errors by users, bounds checks must + * operate on local variables, which accounts for some odd-looking + * inline assignments below. + */ + + static final Node tabAt(AtomicReferenceArray tab, int i) { // used by Iter + return tab.get(i); + } + + private static final boolean casTabAt(AtomicReferenceArray tab, int i, Node c, Node v) { + return tab.compareAndSet(i, c, v); + } + + private static final void setTabAt(AtomicReferenceArray tab, int i, Node v) { + tab.set(i, v); + } + + /* ---------------- Nodes -------------- */ + + /** + * Key-value entry. Note that this is never exported out as a + * user-visible Map.Entry (see MapEntry below). Nodes with a hash + * field of MOVED are special, and do not contain user keys or + * values. Otherwise, keys are never null, and null val fields + * indicate that a node is in the process of being deleted or + * created. For purposes of read-only access, a key may be read + * before a val, but can only be used after checking val to be + * non-null. + */ + static class Node { + volatile int hash; + final Object key; + volatile Object val; + volatile Node next; + + static AtomicIntegerFieldUpdater HASH_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Node.class, "hash"); + + Node(int hash, Object key, Object val, Node next) { + this.hash = hash; + this.key = key; + this.val = val; + this.next = next; + } + + /** CompareAndSet the hash field */ + final boolean casHash(int cmp, int val) { + return HASH_UPDATER.compareAndSet(this, cmp, val); + } + + /** The number of spins before blocking for a lock */ + static final int MAX_SPINS = + Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1; + + /** + * Spins a while if LOCKED bit set and this node is the first + * of its bin, and then sets WAITING bits on hash field and + * blocks (once) if they are still set. It is OK for this + * method to return even if lock is not available upon exit, + * which enables these simple single-wait mechanics. + * + * The corresponding signalling operation is performed within + * callers: Upon detecting that WAITING has been set when + * unlocking lock (via a failed CAS from non-waiting LOCKED + * state), unlockers acquire the sync lock and perform a + * notifyAll. + * + * The initial sanity check on tab and bounds is not currently + * necessary in the only usages of this method, but enables + * use in other future contexts. + */ + final void tryAwaitLock(AtomicReferenceArray tab, int i) { + if (tab != null && i >= 0 && i < tab.length()) { // sanity check + int r = ThreadLocalRandom.current().nextInt(); // randomize spins + int spins = MAX_SPINS, h; + while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { + if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0 && --spins == 0) + Thread.yield(); // yield before block + } + else if (casHash(h, h | WAITING)) { + synchronized (this) { + if (tabAt(tab, i) == this && + (hash & WAITING) == WAITING) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + else + notifyAll(); // possibly won race vs signaller + } + break; + } + } + } + } + } + + /* ---------------- TreeBins -------------- */ + + /** + * Nodes for use in TreeBins + */ + static final class TreeNode extends Node { + TreeNode parent; // red-black tree links + TreeNode left; + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + + TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { + super(hash, key, val, next); + this.parent = parent; + } + } + + /** + * A specialized form of red-black tree for use in bins + * whose size exceeds a threshold. + * + * TreeBins use a special form of comparison for search and + * related operations (which is the main reason we cannot use + * existing collections such as TreeMaps). TreeBins contain + * Comparable elements, but may contain others, as well as + * elements that are Comparable but not necessarily Comparable + * for the same T, so we cannot invoke compareTo among them. To + * handle this, the tree is ordered primarily by hash value, then + * by getClass().getName() order, and then by Comparator order + * among elements of the same class. On lookup at a node, if + * elements are not comparable or compare as 0, both left and + * right children may need to be searched in the case of tied hash + * values. (This corresponds to the full list search that would be + * necessary if all elements were non-Comparable and had tied + * hashes.) The red-black balancing code is updated from + * pre-jdk-collections + * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) + * based in turn on Cormen, Leiserson, and Rivest "Introduction to + * Algorithms" (CLR). + * + * TreeBins also maintain a separate locking discipline than + * regular bins. Because they are forwarded via special MOVED + * nodes at bin heads (which can never change once established), + * we cannot use those nodes as locks. Instead, TreeBin + * extends AbstractQueuedSynchronizer to support a simple form of + * read-write lock. For update operations and table validation, + * the exclusive form of lock behaves in the same way as bin-head + * locks. However, lookups use shared read-lock mechanics to allow + * multiple readers in the absence of writers. Additionally, + * these lookups do not ever block: While the lock is not + * available, they proceed along the slow traversal path (via + * next-pointers) until the lock becomes available or the list is + * exhausted, whichever comes first. (These cases are not fast, + * but maximize aggregate expected throughput.) The AQS mechanics + * for doing this are straightforward. The lock state is held as + * AQS getState(). Read counts are negative; the write count (1) + * is positive. There are no signalling preferences among readers + * and writers. Since we don't need to export full Lock API, we + * just override the minimal AQS methods and use them directly. + */ + static final class TreeBin extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 2249069246763182397L; + transient TreeNode root; // root of tree + transient TreeNode first; // head of next-pointer list + + /* AQS overrides */ + public final boolean isHeldExclusively() { return getState() > 0; } + public final boolean tryAcquire(int ignore) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + public final boolean tryRelease(int ignore) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + public final int tryAcquireShared(int ignore) { + for (int c;;) { + if ((c = getState()) > 0) + return -1; + if (compareAndSetState(c, c -1)) + return 1; + } + } + public final boolean tryReleaseShared(int ignore) { + int c; + do {} while (!compareAndSetState(c = getState(), c + 1)); + return c == -1; + } + + /** From CLR */ + private void rotateLeft(TreeNode p) { + if (p != null) { + TreeNode r = p.right, pp, rl; + if ((rl = p.right = r.left) != null) + rl.parent = p; + if ((pp = r.parent = p.parent) == null) + root = r; + else if (pp.left == p) + pp.left = r; + else + pp.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeNode p) { + if (p != null) { + TreeNode l = p.left, pp, lr; + if ((lr = p.left = l.right) != null) + lr.parent = p; + if ((pp = l.parent = p.parent) == null) + root = l; + else if (pp.right == p) + pp.right = l; + else + pp.left = l; + l.right = p; + p.parent = l; + } + } + + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, Object k, TreeNode p) { + return getTreeNode(h, (RubyObject)k, p); + } + + /** + * Returns the TreeNode (or null if not found) for the given key + * starting at given root. + */ + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, RubyObject k, TreeNode p) { + RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); + while (p != null) { + int dir, ph; RubyObject pk; RubyClass pc; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = (RubyClass)pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pl, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + // try to continue iterating on the left side + else if ((pl = p.left) != null && h <= pl.hash) + dir = -1; + else // no matching node found + return null; + } + } + } + else + dir = (h < ph) ? -1 : 1; + p = (dir > 0) ? p.right : p.left; + } + return null; + } + + int rubyCompare(RubyObject l, RubyObject r) { + ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); + IRubyObject result; + try { + result = l.callMethod(context, "<=>", r); + } catch (RaiseException e) { + // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys + if (context.runtime.getNoMethodError().isInstance(e.getException())) { + return 0; + } + throw e; + } + + return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); + } + + /** + * Wrapper for getTreeNode used by CHM.get. Tries to obtain + * read-lock to call getTreeNode, but during failure to get + * lock, searches along next links. + */ + final Object getValue(int h, Object k) { + Node r = null; + int c = getState(); // Must read lock state first + for (Node e = first; e != null; e = e.next) { + if (c <= 0 && compareAndSetState(c, c - 1)) { + try { + r = getTreeNode(h, k, root); + } finally { + releaseShared(0); + } + break; + } + else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { + r = e; + break; + } + else + c = getState(); + } + return r == null ? null : r.val; + } + + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, Object k, Object v) { + return putTreeNode(h, (RubyObject)k, v); + } + + /** + * Finds or adds a node. + * @return null if added + */ + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, RubyObject k, Object v) { + RubyClass c = k.getMetaClass(); + boolean kNotComparable = !k.respondsTo("<=>"); + TreeNode pp = root, p = null; + int dir = 0; + while (pp != null) { // find existing node or leaf to insert at + int ph; RubyObject pk; RubyClass pc; + p = pp; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + else // continue descending down the left subtree + dir = -1; + } + } + } + else + dir = (h < ph) ? -1 : 1; + pp = (dir > 0) ? p.right : p.left; + } + + TreeNode f = first; + TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); + if (p == null) + root = x; + else { // attach and rebalance; adapted from CLR + TreeNode xp, xpp; + if (f != null) + f.prev = x; + if (dir <= 0) + p.left = x; + else + p.right = x; + x.red = true; + while (x != null && (xp = x.parent) != null && xp.red && + (xpp = xp.parent) != null) { + TreeNode xppl = xpp.left; + if (xp == xppl) { + TreeNode y = xpp.right; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.right) { + rotateLeft(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateRight(xpp); + } + } + } + } + else { + TreeNode y = xppl; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.left) { + rotateRight(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateLeft(xpp); + } + } + } + } + } + TreeNode r = root; + if (r != null && r.red) + r.red = false; + } + return null; + } + + /** + * Removes the given node, that must be present before this + * call. This is messier than typical red-black deletion code + * because we cannot swap the contents of an interior node + * with a leaf successor that is pinned by "next" pointers + * that are accessible independently of lock. So instead we + * swap the tree linkages. + */ + final void deleteTreeNode(TreeNode p) { + TreeNode next = (TreeNode)p.next; // unlink traversal pointers + TreeNode pred = p.prev; + if (pred == null) + first = next; + else + pred.next = next; + if (next != null) + next.prev = pred; + TreeNode replacement; + TreeNode pl = p.left; + TreeNode pr = p.right; + if (pl != null && pr != null) { + TreeNode s = pr, sl; + while ((sl = s.left) != null) // find successor + s = sl; + boolean c = s.red; s.red = p.red; p.red = c; // swap colors + TreeNode sr = s.right; + TreeNode pp = p.parent; + if (s == pr) { // p was s's direct parent + p.parent = s; + s.right = p; + } + else { + TreeNode sp = s.parent; + if ((p.parent = sp) != null) { + if (s == sp.left) + sp.left = p; + else + sp.right = p; + } + if ((s.right = pr) != null) + pr.parent = s; + } + p.left = null; + if ((p.right = sr) != null) + sr.parent = p; + if ((s.left = pl) != null) + pl.parent = s; + if ((s.parent = pp) == null) + root = s; + else if (p == pp.left) + pp.left = s; + else + pp.right = s; + replacement = sr; + } + else + replacement = (pl != null) ? pl : pr; + TreeNode pp = p.parent; + if (replacement == null) { + if (pp == null) { + root = null; + return; + } + replacement = p; + } + else { + replacement.parent = pp; + if (pp == null) + root = replacement; + else if (p == pp.left) + pp.left = replacement; + else + pp.right = replacement; + p.left = p.right = p.parent = null; + } + if (!p.red) { // rebalance, from CLR + TreeNode x = replacement; + while (x != null) { + TreeNode xp, xpl; + if (x.red || (xp = x.parent) == null) { + x.red = false; + break; + } + if (x == (xpl = xp.left)) { + TreeNode sib = xp.right; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateLeft(xp); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sr == null || !sr.red) && + (sl == null || !sl.red)) { + sib.red = true; + x = xp; + } + else { + if (sr == null || !sr.red) { + if (sl != null) + sl.red = false; + sib.red = true; + rotateRight(sib); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sr = sib.right) != null) + sr.red = false; + } + if (xp != null) { + xp.red = false; + rotateLeft(xp); + } + x = root; + } + } + } + else { // symmetric + TreeNode sib = xpl; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateRight(xp); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sl == null || !sl.red) && + (sr == null || !sr.red)) { + sib.red = true; + x = xp; + } + else { + if (sl == null || !sl.red) { + if (sr != null) + sr.red = false; + sib.red = true; + rotateLeft(sib); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sl = sib.left) != null) + sl.red = false; + } + if (xp != null) { + xp.red = false; + rotateRight(xp); + } + x = root; + } + } + } + } + } + if (p == replacement && (pp = p.parent) != null) { + if (p == pp.left) // detach pointers + pp.left = null; + else if (p == pp.right) + pp.right = null; + p.parent = null; + } + } + } + + /* ---------------- Collision reduction methods -------------- */ + + /** + * Spreads higher bits to lower, and also forces top 2 bits to 0. + * Because the table uses power-of-two masking, sets of hashes + * that vary only in bits above the current mask will always + * collide. (Among known examples are sets of Float keys holding + * consecutive whole numbers in small tables.) To counter this, + * we apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed across bits (so don't benefit + * from spreading), and because we use trees to handle large sets + * of collisions in bins, we don't need excessively high quality. + */ + private static final int spread(int h) { + h ^= (h >>> 18) ^ (h >>> 12); + return (h ^ (h >>> 10)) & HASH_BITS; + } + + /** + * Replaces a list bin with a tree bin. Call only when locked. + * Fails to replace if the given key is non-comparable or table + * is, or needs, resizing. + */ + private final void replaceWithTreeBin(AtomicReferenceArray tab, int index, Object key) { + if ((key instanceof Comparable) && + (tab.length() >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { + TreeBin t = new TreeBin(); + for (Node e = tabAt(tab, index); e != null; e = e.next) + t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); + setTabAt(tab, index, new Node(MOVED, t, null, null)); + } + } + + /* ---------------- Internal access and update methods -------------- */ + + /** Implementation for get and containsKey */ + private final Object internalGet(Object k) { + int h = spread(k.hashCode()); + retry: for (AtomicReferenceArray tab = table; tab != null;) { + Node e, p; Object ek, ev; int eh; // locals to read fields once + for (e = tabAt(tab, (tab.length() - 1) & h); e != null; e = e.next) { + if ((eh = e.hash) == MOVED) { + if ((ek = e.key) instanceof TreeBin) // search TreeBin + return ((TreeBin)ek).getValue(h, k); + else { // restart with new table + tab = (AtomicReferenceArray)ek; + continue retry; + } + } + else if ((eh & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + } + break; + } + return null; + } + + /** + * Implementation for the four public remove/replace methods: + * Replaces node value with v, conditional upon match of cv if + * non-null. If resulting value is null, delete. + */ + private final Object internalReplace(Object k, Object v, Object cv) { + int h = spread(k.hashCode()); + Object oldVal = null; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null || + (f = tabAt(tab, i = (tab.length() - 1) & h)) == null) + break; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + boolean deleted = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) { + Object pv = p.val; + if (cv == null || cv == pv || cv.equals(pv)) { + oldVal = pv; + if ((p.val = v) == null) { + deleted = true; + t.deleteTreeNode(p); + } + } + } + } + } finally { + t.release(0); + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) != h && f.next == null) // precheck + break; // rules out possible existence + else if ((fh & LOCKED) != 0) { + checkForResize(); // try resizing if can't get lock + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + boolean validated = false; + boolean deleted = false; + try { + if (tabAt(tab, i) == f) { + validated = true; + for (Node e = f, pred = null;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + ((ev = e.val) != null) && + ((ek = e.key) == k || k.equals(ek))) { + if (cv == null || cv == ev || cv.equals(ev)) { + oldVal = ev; + if ((e.val = v) == null) { + deleted = true; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + } + break; + } + pred = e; + if ((e = e.next) == null) + break; + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + } + return oldVal; + } + + /* + * Internal versions of the six insertion methods, each a + * little more complicated than the last. All have + * the same basic structure as the first (internalPut): + * 1. If table uninitialized, create + * 2. If bin empty, try to CAS new node + * 3. If bin stale, use new table + * 4. if bin converted to TreeBin, validate and relay to TreeBin methods + * 5. Lock and validate; if valid, scan and add or update + * + * The others interweave other checks and/or alternative actions: + * * Plain put checks for and performs resize after insertion. + * * putIfAbsent prescans for mapping without lock (and fails to add + * if present), which also makes pre-emptive resize checks worthwhile. + * * computeIfAbsent extends form used in putIfAbsent with additional + * mechanics to deal with, calls, potential exceptions and null + * returns from function call. + * * compute uses the same function-call mechanics, but without + * the prescans + * * merge acts as putIfAbsent in the absent case, but invokes the + * update function if present + * * putAll attempts to pre-allocate enough table space + * and more lazily performs count updates and checks. + * + * Someday when details settle down a bit more, it might be worth + * some factoring to reduce sprawl. + */ + + /** Implementation for put */ + private final Object internalPut(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; // no lock when adding to empty bin + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) { + oldVal = p.val; + p.val = v; + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { // needed in case equals() throws + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { // unlock and signal if needed + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for putIfAbsent */ + private final Object internalPutIfAbsent(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) + oldVal = p.val; + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { // at least 2 nodes -- search and maybe resize + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for computeIfAbsent */ + private final Object internalComputeIfAbsent(K k, + Fun mf) { + int h = spread(k.hashCode()); + Object val = null; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + count = 1; + try { + if ((val = mf.apply(k)) != null) + node.val = val; + } finally { + if (val == null) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean added = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + val = p.val; + else if ((val = mf.apply(k)) != null) { + added = true; + count = 2; + t.putTreeNode(h, k, val); + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (!added) + return val; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + boolean added = false; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + if ((val = mf.apply(k)) != null) { + added = true; + last.next = new Node(h, k, val, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (!added) + return val; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + } + if (val != null) { + counter.add(1L); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for compute */ + @SuppressWarnings("unchecked") private final Object internalCompute + (K k, boolean onlyIfPresent, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (onlyIfPresent) + break; + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + try { + count = 1; + if ((val = mf.apply(k, null)) != null) { + node.val = val; + delta = 1; + } + } finally { + if (delta == 0) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + Object pv; + if (p == null) { + if (onlyIfPresent) + break; + pv = null; + } else + pv = p.val; + if ((val = mf.apply(k, (V)pv)) != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply(k, (V)ev); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length() <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for merge */ + @SuppressWarnings("unchecked") private final Object internalMerge + (K k, V v, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + delta = 1; + val = v; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + val = (p == null) ? v : mf.apply((V)p.val, v); + if (val != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply((V)ev, v); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + val = v; + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length() <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for putAll */ + private final void internalPutAll(Map m) { + tryPresize(m.size()); + long delta = 0L; // number of uncommitted additions + boolean npe = false; // to throw exception on exit for nulls + try { // to clean up counts on other exceptions + for (Map.Entry entry : m.entrySet()) { + Object k, v; + if (entry == null || (k = entry.getKey()) == null || + (v = entry.getValue()) == null) { + npe = true; + break; + } + int h = spread(k.hashCode()); + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null){ + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + ++delta; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + p.val = v; + else { + t.putTreeNode(h, k, v); + ++delta; + } + } + } finally { + t.release(0); + } + if (validated) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); + delta = 0L; + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + int count = 0; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + ++delta; + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (count > 1) { + counter.add(delta); + delta = 0L; + checkForResize(); + } + break; + } + } + } + } + } finally { + if (delta != 0) + counter.add(delta); + } + if (npe) + throw new NullPointerException(); + } + + /* ---------------- Table Initialization and Resizing -------------- */ + + /** + * Returns a power of two table size for the given desired capacity. + * See Hackers Delight, sec 3.2 + */ + private static final int tableSizeFor(int c) { + int n = c - 1; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + } + + /** + * Initializes table, using the size recorded in sizeCtl. + */ + private final AtomicReferenceArray initTable() { + AtomicReferenceArray tab; int sc; + while ((tab = table) == null) { + if ((sc = sizeCtl) < 0) + Thread.yield(); // lost initialization race; just spin + else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if ((tab = table) == null) { + int n = (sc > 0) ? sc : DEFAULT_CAPACITY; + tab = table = new AtomicReferenceArray(n); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + break; + } + } + return tab; + } + + /** + * If table is too small and not already resizing, creates next + * table and transfers bins. Rechecks occupancy after a transfer + * to see if another resize is already needed because resizings + * are lagging additions. + */ + private final void checkForResize() { + AtomicReferenceArray tab; int n, sc; + while ((tab = table) != null && + (n = tab.length()) < MAXIMUM_CAPACITY && + (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && + SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (tab == table) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + + /** + * Tries to presize table to accommodate the given number of elements. + * + * @param size number of elements (doesn't need to be perfectly accurate) + */ + private final void tryPresize(int size) { + int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : + tableSizeFor(size + (size >>> 1) + 1); + int sc; + while ((sc = sizeCtl) >= 0) { + AtomicReferenceArray tab = table; int n; + if (tab == null || (n = tab.length()) == 0) { + n = (sc > c) ? sc : c; + if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == tab) { + table = new AtomicReferenceArray(n); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + } + } + else if (c <= sc || n >= MAXIMUM_CAPACITY) + break; + else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == tab) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + } + + /* + * Moves and/or copies the nodes in each bin to new table. See + * above for explanation. + * + * @return the new table + */ + private static final AtomicReferenceArray rebuild(AtomicReferenceArray tab) { + int n = tab.length(); + AtomicReferenceArray nextTab = new AtomicReferenceArray(n << 1); + Node fwd = new Node(MOVED, nextTab, null, null); + int[] buffer = null; // holds bins to revisit; null until needed + Node rev = null; // reverse forwarder; null until needed + int nbuffered = 0; // the number of bins in buffer list + int bufferIndex = 0; // buffer index of current buffered bin + int bin = n - 1; // current non-buffered bin or -1 if none + + for (int i = bin;;) { // start upwards sweep + int fh; Node f; + if ((f = tabAt(tab, i)) == null) { + if (bin >= 0) { // Unbuffered; no lock needed (or available) + if (!casTabAt(tab, i, f, fwd)) + continue; + } + else { // transiently use a locked forwarding node + Node g = new Node(MOVED|LOCKED, nextTab, null, null); + if (!casTabAt(tab, i, f, g)) + continue; + setTabAt(nextTab, i, null); + setTabAt(nextTab, i + n, null); + setTabAt(tab, i, fwd); + if (!g.casHash(MOVED|LOCKED, MOVED)) { + g.hash = MOVED; + synchronized (g) { g.notifyAll(); } + } + } + } + else if ((fh = f.hash) == MOVED) { + Object fk = f.key; + if (fk instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + splitTreeBin(nextTab, i, t); + setTabAt(tab, i, fwd); + } + } finally { + t.release(0); + } + if (!validated) + continue; + } + } + else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { + boolean validated = false; + try { // split to lo and hi lists; copying as needed + if (tabAt(tab, i) == f) { + validated = true; + splitBin(nextTab, i, f); + setTabAt(tab, i, fwd); + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (!validated) + continue; + } + else { + if (buffer == null) // initialize buffer for revisits + buffer = new int[TRANSFER_BUFFER_SIZE]; + if (bin < 0 && bufferIndex > 0) { + int j = buffer[--bufferIndex]; + buffer[bufferIndex] = i; + i = j; // swap with another bin + continue; + } + if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { + f.tryAwaitLock(tab, i); + continue; // no other options -- block + } + if (rev == null) // initialize reverse-forwarder + rev = new Node(MOVED, tab, null, null); + if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) + continue; // recheck before adding to list + buffer[nbuffered++] = i; + setTabAt(nextTab, i, rev); // install place-holders + setTabAt(nextTab, i + n, rev); + } + + if (bin > 0) + i = --bin; + else if (buffer != null && nbuffered > 0) { + bin = -1; + i = buffer[bufferIndex = --nbuffered]; + } + else + return nextTab; + } + } + + /** + * Splits a normal bin with list headed by e into lo and hi parts; + * installs in given table. + */ + private static void splitBin(AtomicReferenceArray nextTab, int i, Node e) { + int bit = nextTab.length() >>> 1; // bit to split on + int runBit = e.hash & bit; + Node lastRun = e, lo = null, hi = null; + for (Node p = e.next; p != null; p = p.next) { + int b = p.hash & bit; + if (b != runBit) { + runBit = b; + lastRun = p; + } + } + if (runBit == 0) + lo = lastRun; + else + hi = lastRun; + for (Node p = e; p != lastRun; p = p.next) { + int ph = p.hash & HASH_BITS; + Object pk = p.key, pv = p.val; + if ((ph & bit) == 0) + lo = new Node(ph, pk, pv, lo); + else + hi = new Node(ph, pk, pv, hi); + } + setTabAt(nextTab, i, lo); + setTabAt(nextTab, i + bit, hi); + } + + /** + * Splits a tree bin into lo and hi parts; installs in given table. + */ + private static void splitTreeBin(AtomicReferenceArray nextTab, int i, TreeBin t) { + int bit = nextTab.length() >>> 1; + TreeBin lt = new TreeBin(); + TreeBin ht = new TreeBin(); + int lc = 0, hc = 0; + for (Node e = t.first; e != null; e = e.next) { + int h = e.hash & HASH_BITS; + Object k = e.key, v = e.val; + if ((h & bit) == 0) { + ++lc; + lt.putTreeNode(h, k, v); + } + else { + ++hc; + ht.putTreeNode(h, k, v); + } + } + Node ln, hn; // throw away trees if too small + if (lc <= (TREE_THRESHOLD >>> 1)) { + ln = null; + for (Node p = lt.first; p != null; p = p.next) + ln = new Node(p.hash, p.key, p.val, ln); + } + else + ln = new Node(MOVED, lt, null, null); + setTabAt(nextTab, i, ln); + if (hc <= (TREE_THRESHOLD >>> 1)) { + hn = null; + for (Node p = ht.first; p != null; p = p.next) + hn = new Node(p.hash, p.key, p.val, hn); + } + else + hn = new Node(MOVED, ht, null, null); + setTabAt(nextTab, i + bit, hn); + } + + /** + * Implementation for clear. Steps through each bin, removing all + * nodes. + */ + private final void internalClear() { + long delta = 0L; // negative number of deletions + int i = 0; + AtomicReferenceArray tab = table; + while (tab != null && i < tab.length()) { + int fh; Object fk; + Node f = tabAt(tab, i); + if (f == null) + ++i; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + for (Node p = t.first; p != null; p = p.next) { + if (p.val != null) { // (currently always true) + p.val = null; + --delta; + } + } + t.first = null; + t.root = null; + ++i; + } + } finally { + t.release(0); + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); // opportunistically update count + delta = 0L; + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + for (Node e = f; e != null; e = e.next) { + if (e.val != null) { // (currently always true) + e.val = null; + --delta; + } + } + setTabAt(tab, i, null); + ++i; + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + } + } + if (delta != 0) + counter.add(delta); + } + + /* ----------------Table Traversal -------------- */ + + /** + * Encapsulates traversal for methods such as containsValue; also + * serves as a base class for other iterators and bulk tasks. + * + * At each step, the iterator snapshots the key ("nextKey") and + * value ("nextVal") of a valid node (i.e., one that, at point of + * snapshot, has a non-null user value). Because val fields can + * change (including to null, indicating deletion), field nextVal + * might not be accurate at point of use, but still maintains the + * weak consistency property of holding a value that was once + * valid. To support iterator.remove, the nextKey field is not + * updated (nulled out) when the iterator cannot advance. + * + * Internal traversals directly access these fields, as in: + * {@code while (it.advance() != null) { process(it.nextKey); }} + * + * Exported iterators must track whether the iterator has advanced + * (in hasNext vs next) (by setting/checking/nulling field + * nextVal), and then extract key, value, or key-value pairs as + * return values of next(). + * + * The iterator visits once each still-valid node that was + * reachable upon iterator construction. It might miss some that + * were added to a bin after the bin was visited, which is OK wrt + * consistency guarantees. Maintaining this property in the face + * of possible ongoing resizes requires a fair amount of + * bookkeeping state that is difficult to optimize away amidst + * volatile accesses. Even so, traversal maintains reasonable + * throughput. + * + * Normally, iteration proceeds bin-by-bin traversing lists. + * However, if the table has been resized, then all future steps + * must traverse both the bin at the current index as well as at + * (index + baseSize); and so on for further resizings. To + * paranoically cope with potential sharing by users of iterators + * across threads, iteration terminates if a bounds checks fails + * for a table read. + * + * This class extends ForkJoinTask to streamline parallel + * iteration in bulk operations (see BulkTask). This adds only an + * int of space overhead, which is close enough to negligible in + * cases where it is not needed to not worry about it. Because + * ForkJoinTask is Serializable, but iterators need not be, we + * need to add warning suppressions. + */ + @SuppressWarnings("serial") static class Traverser { + final ConcurrentHashMapV8 map; + Node next; // the next entry to use + K nextKey; // cached key field of next + V nextVal; // cached val field of next + AtomicReferenceArray tab; // current table; updated if resized + int index; // index of bin to use next + int baseIndex; // current index of initial table + int baseLimit; // index bound for initial table + int baseSize; // initial table size + + /** Creates iterator for all entries in the table. */ + Traverser(ConcurrentHashMapV8 map) { + this.map = map; + } + + /** Creates iterator for split() methods */ + Traverser(Traverser it) { + ConcurrentHashMapV8 m; AtomicReferenceArray t; + if ((m = this.map = it.map) == null) + t = null; + else if ((t = it.tab) == null && // force parent tab initialization + (t = it.tab = m.table) != null) + it.baseLimit = it.baseSize = t.length(); + this.tab = t; + this.baseSize = it.baseSize; + it.baseLimit = this.index = this.baseIndex = + ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; + } + + /** + * Advances next; returns nextVal or null if terminated. + * See above for explanation. + */ + final V advance() { + Node e = next; + V ev = null; + outer: do { + if (e != null) // advance past used/skipped node + e = e.next; + while (e == null) { // get to next non-null bin + ConcurrentHashMapV8 m; + AtomicReferenceArray t; int b, i, n; Object ek; // checks must use locals + if ((t = tab) != null) + n = t.length(); + else if ((m = map) != null && (t = tab = m.table) != null) + n = baseLimit = baseSize = t.length(); + else + break outer; + if ((b = baseIndex) >= baseLimit || + (i = index) < 0 || i >= n) + break outer; + if ((e = tabAt(t, i)) != null && e.hash == MOVED) { + if ((ek = e.key) instanceof TreeBin) + e = ((TreeBin)ek).first; + else { + tab = (AtomicReferenceArray)ek; + continue; // restarts due to null val + } + } // visit upper slots if present + index = (i += baseSize) < n ? i : (baseIndex = b + 1); + } + nextKey = (K) e.key; + } while ((ev = (V) e.val) == null); // skip deleted or special nodes + next = e; + return nextVal = ev; + } + + public final void remove() { + Object k = nextKey; + if (k == null && (advance() == null || (k = nextKey) == null)) + throw new IllegalStateException(); + map.internalReplace(k, null, null); + } + + public final boolean hasNext() { + return nextVal != null || advance() != null; + } + + public final boolean hasMoreElements() { return hasNext(); } + public final void setRawResult(Object x) { } + public R getRawResult() { return null; } + public boolean exec() { return true; } + } + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the default initial table size (16). + */ + public ConcurrentHashMapV8() { + this.counter = new LongAdder(); + } + + /** + * Creates a new, empty map with an initial table size + * accommodating the specified number of elements without the need + * to dynamically resize. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + */ + public ConcurrentHashMapV8(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? + MAXIMUM_CAPACITY : + tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new map with the same mappings as the given map. + * + * @param m the map + */ + public ConcurrentHashMapV8(Map m) { + this.counter = new LongAdder(); + this.sizeCtl = DEFAULT_CAPACITY; + internalPutAll(m); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}) and + * initial table density ({@code loadFactor}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, 1); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}), table + * density ({@code loadFactor}), and number of concurrently + * updating threads ({@code concurrencyLevel}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation may use this value as + * a sizing hint. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive + */ + public ConcurrentHashMapV8(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + if (initialCapacity < concurrencyLevel) // Use at least as many bins + initialCapacity = concurrencyLevel; // as estimated threads + long size = (long)(1.0 + (long)initialCapacity / loadFactor); + int cap = (size >= (long)MAXIMUM_CAPACITY) ? + MAXIMUM_CAPACITY : tableSizeFor((int)size); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @return the new set + */ + public static KeySetView newKeySet() { + return new KeySetView(new ConcurrentHashMapV8(), + Boolean.TRUE); + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + * @return the new set + */ + public static KeySetView newKeySet(int initialCapacity) { + return new KeySetView(new ConcurrentHashMapV8(initialCapacity), + Boolean.TRUE); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return counter.sum() <= 0L; // ignore transient negative values + } + + /** + * {@inheritDoc} + */ + public int size() { + long n = counter.sum(); + return ((n < 0L) ? 0 : + (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : + (int)n); + } + + /** + * Returns the number of mappings. This method should be used + * instead of {@link #size} because a ConcurrentHashMapV8 may + * contain more mappings than can be represented as an int. The + * value returned is a snapshot; the actual count may differ if + * there are ongoing concurrent insertions or removals. + * + * @return the number of mappings + */ + public long mappingCount() { + long n = counter.sum(); + return (n < 0L) ? 0L : n; // ignore transient negative values + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

    More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V get(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalGet(key); + } + + /** + * Returns the value to which the specified key is mapped, + * or the given defaultValue if this map contains no mapping for the key. + * + * @param key the key + * @param defaultValue the value to return if this map contains + * no mapping for the given key + * @return the mapping for the key, if present; else the defaultValue + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { + if (key == null) + throw new NullPointerException(); + V v = (V) internalGet(key); + return v == null ? defaultValue : v; + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return {@code true} if and only if the specified object + * is a key in this table, as determined by the + * {@code equals} method; {@code false} otherwise + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + if (key == null) + throw new NullPointerException(); + return internalGet(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. Note: This method may require a full traversal + * of the map, and is much slower than method {@code containsKey}. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return true; + } + return false; + } + + public K findKey(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return it.nextKey; + } + return null; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + * + * @param value a value to search for + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this table as + * determined by the {@code equals} method; + * {@code false} otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + *

    The value can be retrieved by calling the {@code get} method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPut(key, value); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPutIfAbsent(key, value); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map m) { + internalPutAll(m); + } + + /** + * If the specified key is not already associated with a value, + * computes its value using the given mappingFunction and enters + * it into the map unless null. This is equivalent to + *

     {@code
    +     * if (map.containsKey(key))
    +     *   return map.get(key);
    +     * value = mappingFunction.apply(key);
    +     * if (value != null)
    +     *   map.put(key, value);
    +     * return value;}
    + * + * except that the action is performed atomically. If the + * function returns {@code null} no mapping is recorded. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and no mapping is recorded. Some + * attempted update operations on this map by other threads may be + * blocked while computation is in progress, so the computation + * should be short and simple, and must not attempt to update any + * other mappings of this Map. The most appropriate usage is to + * construct a new object serving as an initial mapped value, or + * memoized result, as in: + * + *
     {@code
    +     * map.computeIfAbsent(key, new Fun() {
    +     *   public V map(K k) { return new Value(f(k)); }});}
    + * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key or mappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, + * in which case the mapping is left unestablished + */ + @SuppressWarnings("unchecked") public V computeIfAbsent + (K key, Fun mappingFunction) { + if (key == null || mappingFunction == null) + throw new NullPointerException(); + return (V)internalComputeIfAbsent(key, mappingFunction); + } + + /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
     {@code
    +     *   if (map.containsKey(key)) {
    +     *     value = remappingFunction.apply(key, map.get(key));
    +     *     if (value != null)
    +     *       map.put(key, value);
    +     *     else
    +     *       map.remove(key);
    +     *   }
    +     * }
    + * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V computeIfPresent + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** + * Computes a new mapping value given a key and + * its current mapped value (or {@code null} if there is no current + * mapping). This is equivalent to + *
     {@code
    +     *   value = remappingFunction.apply(key, map.get(key));
    +     *   if (value != null)
    +     *     map.put(key, value);
    +     *   else
    +     *     map.remove(key);
    +     * }
    + * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + *
     {@code
    +     * Map map = ...;
    +     * final String msg = ...;
    +     * map.compute(key, new BiFun() {
    +     *   public String apply(Key k, String v) {
    +     *    return (v == null) ? msg : v + msg;});}}
    + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V compute + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
     {@code
    +     *   if (!map.containsKey(key))
    +     *     map.put(value);
    +     *   else {
    +     *     newValue = remappingFunction.apply(map.get(key), value);
    +     *     if (value != null)
    +     *       map.put(key, value);
    +     *     else
    +     *       map.remove(key);
    +     *   }
    +     * }
    + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + @SuppressWarnings("unchecked") public V merge + (K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V remove(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalReplace(key, null, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return internalReplace(key, null, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (key == null || oldValue == null || newValue == null) + throw new NullPointerException(); + return internalReplace(key, newValue, oldValue) != null; + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V replace(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalReplace(key, value, null); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + internalClear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. + * + * @return the set view + */ + public KeySetView keySet() { + KeySetView ks = keySet; + return (ks != null) ? ks : (keySet = new KeySetView(this, null)); + } + + /** + * Returns a {@link Set} view of the keys in this map, using the + * given common mapped value for any additions (i.e., {@link + * Collection#add} and {@link Collection#addAll}). This is of + * course only appropriate if it is acceptable to use the same + * value for all additions from this view. + * + * @param mappedValue the mapped value to use for any + * additions. + * @return the set view + * @throws NullPointerException if the mappedValue is null + */ + public KeySetView keySet(V mappedValue) { + if (mappedValue == null) + throw new NullPointerException(); + return new KeySetView(this, mappedValue); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. + */ + public ValuesView values() { + ValuesView vs = values; + return (vs != null) ? vs : (values = new ValuesView(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. + * + *

    The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set> entrySet() { + EntrySetView es = entrySet; + return (es != null) ? es : (entrySet = new EntrySetView(this)); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet() + */ + public Enumeration keys() { + return new KeyIterator(this); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values() + */ + public Enumeration elements() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the keys in this map. + * + * @return a partitionable iterator of the keys in this map + */ + public Spliterator keySpliterator() { + return new KeyIterator(this); + } + + /** + * Returns a partitionable iterator of the values in this map. + * + * @return a partitionable iterator of the values in this map + */ + public Spliterator valueSpliterator() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the entries in this map. + * + * @return a partitionable iterator of the entries in this map + */ + public Spliterator> entrySpliterator() { + return new EntryIterator(this); + } + + /** + * Returns the hash code value for this {@link Map}, i.e., + * the sum of, for each key-value pair in the map, + * {@code key.hashCode() ^ value.hashCode()}. + * + * @return the hash code value for this map + */ + public int hashCode() { + int h = 0; + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + h += it.nextKey.hashCode() ^ v.hashCode(); + } + return h; + } + + /** + * Returns a string representation of this map. The string + * representation consists of a list of key-value mappings (in no + * particular order) enclosed in braces ("{@code {}}"). Adjacent + * mappings are separated by the characters {@code ", "} (comma + * and space). Each key-value mapping is rendered as the key + * followed by an equals sign ("{@code =}") followed by the + * associated value. + * + * @return a string representation of this map + */ + public String toString() { + Traverser it = new Traverser(this); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + Object v; + if ((v = it.advance()) != null) { + for (;;) { + Object k = it.nextKey; + sb.append(k == this ? "(this Map)" : k); + sb.append('='); + sb.append(v == this ? "(this Map)" : v); + if ((v = it.advance()) == null) + break; + sb.append(',').append(' '); + } + } + return sb.append('}').toString(); + } + + /** + * Compares the specified object with this map for equality. + * Returns {@code true} if the given object is a map with the same + * mappings as this map. This operation may return misleading + * results if either map is concurrently modified during execution + * of this method. + * + * @param o object to be compared for equality with this map + * @return {@code true} if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o != this) { + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + Traverser it = new Traverser(this); + Object val; + while ((val = it.advance()) != null) { + Object v = m.get(it.nextKey); + if (v == null || (v != val && !v.equals(val))) + return false; + } + for (Map.Entry e : m.entrySet()) { + Object mk, mv, v; + if ((mk = e.getKey()) == null || + (mv = e.getValue()) == null || + (v = internalGet(mk)) == null || + (mv != v && !mv.equals(v))) + return false; + } + } + return true; + } + + /* ----------------Iterators -------------- */ + + @SuppressWarnings("serial") static final class KeyIterator extends Traverser + implements Spliterator, Enumeration { + KeyIterator(ConcurrentHashMapV8 map) { super(map); } + KeyIterator(Traverser it) { + super(it); + } + public KeyIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new KeyIterator(this); + } + @SuppressWarnings("unchecked") public final K next() { + if (nextVal == null && advance() == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return (K) k; + } + + public final K nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class ValueIterator extends Traverser + implements Spliterator, Enumeration { + ValueIterator(ConcurrentHashMapV8 map) { super(map); } + ValueIterator(Traverser it) { + super(it); + } + public ValueIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new ValueIterator(this); + } + + @SuppressWarnings("unchecked") public final V next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + nextVal = null; + return (V) v; + } + + public final V nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class EntryIterator extends Traverser + implements Spliterator> { + EntryIterator(ConcurrentHashMapV8 map) { super(map); } + EntryIterator(Traverser it) { + super(it); + } + public EntryIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new EntryIterator(this); + } + + @SuppressWarnings("unchecked") public final Map.Entry next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return new MapEntry((K)k, (V)v, map); + } + } + + /** + * Exported Entry for iterators + */ + static final class MapEntry implements Map.Entry { + final K key; // non-null + V val; // non-null + final ConcurrentHashMapV8 map; + MapEntry(K key, V val, ConcurrentHashMapV8 map) { + this.key = key; + this.val = val; + this.map = map; + } + public final K getKey() { return key; } + public final V getValue() { return val; } + public final int hashCode() { return key.hashCode() ^ val.hashCode(); } + public final String toString(){ return key + "=" + val; } + + public final boolean equals(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + (k == key || k.equals(key)) && + (v == val || v.equals(val))); + } + + /** + * Sets our entry's value and writes through to the map. The + * value to return is somewhat arbitrary here. Since we do not + * necessarily track asynchronous changes, the most recent + * "previous" value could be different from what we return (or + * could even have been removed in which case the put will + * re-establish). We do not and cannot guarantee more. + */ + public final V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = val; + val = value; + map.put(key, value); + return v; + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Stripped-down version of helper class used in previous version, + * declared for the sake of serialization compatibility + */ + static class Segment implements Serializable { + private static final long serialVersionUID = 2249069246763182397L; + final float loadFactor; + Segment(float lf) { this.loadFactor = lf; } + } + + /** + * Saves the state of the {@code ConcurrentHashMapV8} instance to a + * stream (i.e., serializes it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + if (segments == null) { // for serialization compatibility + segments = (Segment[]) + new Segment[DEFAULT_CONCURRENCY_LEVEL]; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(LOAD_FACTOR); + } + s.defaultWriteObject(); + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + s.writeObject(it.nextKey); + s.writeObject(v); + } + s.writeObject(null); + s.writeObject(null); + segments = null; // throw away + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + this.segments = null; // unneeded + // initialize transient final field + this.counter = new LongAdder(); + + // Create all nodes, then place in table once size is known + long size = 0L; + Node p = null; + for (;;) { + K k = (K) s.readObject(); + V v = (V) s.readObject(); + if (k != null && v != null) { + int h = spread(k.hashCode()); + p = new Node(h, k, v, p); + ++size; + } + else + break; + } + if (p != null) { + boolean init = false; + int n; + if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) + n = MAXIMUM_CAPACITY; + else { + int sz = (int)size; + n = tableSizeFor(sz + (sz >>> 1) + 1); + } + int sc = sizeCtl; + boolean collide = false; + if (n > sc && + SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == null) { + init = true; + AtomicReferenceArray tab = new AtomicReferenceArray(n); + int mask = n - 1; + while (p != null) { + int j = p.hash & mask; + Node next = p.next; + Node q = p.next = tabAt(tab, j); + setTabAt(tab, j, p); + if (!collide && q != null && q.hash == p.hash) + collide = true; + p = next; + } + table = tab; + counter.add(size); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + if (collide) { // rescan and convert to TreeBins + AtomicReferenceArray tab = table; + for (int i = 0; i < tab.length(); ++i) { + int c = 0; + for (Node e = tabAt(tab, i); e != null; e = e.next) { + if (++c > TREE_THRESHOLD && + (e.key instanceof Comparable)) { + replaceWithTreeBin(tab, i, e.key); + break; + } + } + } + } + } + if (!init) { // Can only happen if unsafely published. + while (p != null) { + internalPut(p.key, p.val); + p = p.next; + } + } + } + } + + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + /* ----------------Views -------------- */ + + /** + * Base class for views. + */ + static abstract class CHMView { + final ConcurrentHashMapV8 map; + CHMView(ConcurrentHashMapV8 map) { this.map = map; } + + /** + * Returns the map backing this view. + * + * @return the map backing this view + */ + public ConcurrentHashMapV8 getMap() { return map; } + + public final int size() { return map.size(); } + public final boolean isEmpty() { return map.isEmpty(); } + public final void clear() { map.clear(); } + + // implementations below rely on concrete classes supplying these + abstract public Iterator iterator(); + abstract public boolean contains(Object o); + abstract public boolean remove(Object o); + + private static final String oomeMsg = "Required array size too large"; + + public final Object[] toArray() { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int n = (int)sz; + Object[] r = new Object[n]; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = it.next(); + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int m = (int)sz; + T[] r = (a.length >= m) ? a : + (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), m); + int n = r.length; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = (T)it.next(); + } + if (a == r && i < n) { + r[i] = null; // null-terminate + return r; + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + public final int hashCode() { + int h = 0; + for (Iterator it = iterator(); it.hasNext();) + h += it.next().hashCode(); + return h; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + Iterator it = iterator(); + if (it.hasNext()) { + for (;;) { + Object e = it.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!it.hasNext()) + break; + sb.append(',').append(' '); + } + } + return sb.append(']').toString(); + } + + public final boolean containsAll(Collection c) { + if (c != this) { + for (Iterator it = c.iterator(); it.hasNext();) { + Object e = it.next(); + if (e == null || !contains(e)) + return false; + } + } + return true; + } + + public final boolean removeAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + public final boolean retainAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (!c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in + * which additions may optionally be enabled by mapping to a + * common value. This class cannot be directly instantiated. See + * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, + * {@link #newKeySet(int)}. + */ + public static class KeySetView extends CHMView implements Set, java.io.Serializable { + private static final long serialVersionUID = 7249069246763182397L; + private final V value; + KeySetView(ConcurrentHashMapV8 map, V value) { // non-public + super(map); + this.value = value; + } + + /** + * Returns the default mapped value for additions, + * or {@code null} if additions are not supported. + * + * @return the default mapped value for additions, or {@code null} + * if not supported. + */ + public V getMappedValue() { return value; } + + // implement Set API + + public boolean contains(Object o) { return map.containsKey(o); } + public boolean remove(Object o) { return map.remove(o) != null; } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the keys of this map + */ + public Iterator iterator() { return new KeyIterator(map); } + public boolean add(K e) { + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + if (e == null) + throw new NullPointerException(); + return map.internalPutIfAbsent(e, v) == null; + } + public boolean addAll(Collection c) { + boolean added = false; + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + for (K e : c) { + if (e == null) + throw new NullPointerException(); + if (map.internalPutIfAbsent(e, v) == null) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Collection} of + * values, in which additions are disabled. This class cannot be + * directly instantiated. See {@link #values}, + * + *

    The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public static final class ValuesView extends CHMView + implements Collection { + ValuesView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { return map.containsValue(o); } + public final boolean remove(Object o) { + if (o != null) { + Iterator it = new ValueIterator(map); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + } + return false; + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the values of this map + */ + public final Iterator iterator() { + return new ValueIterator(map); + } + public final boolean add(V e) { + throw new UnsupportedOperationException(); + } + public final boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) + * entries. This class cannot be directly instantiated. See + * {@link #entrySet}. + */ + public static final class EntrySetView extends CHMView + implements Set> { + EntrySetView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { + Object k, v, r; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (r = map.get(k)) != null && + (v = e.getValue()) != null && + (v == r || v.equals(r))); + } + public final boolean remove(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + map.remove(k, v)); + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the entries of this map + */ + public final Iterator> iterator() { + return new EntryIterator(map); + } + + public final boolean add(Entry e) { + K key = e.getKey(); + V value = e.getValue(); + if (key == null || value == null) + throw new NullPointerException(); + return map.internalPut(key, value) == null; + } + public final boolean addAll(Collection> c) { + boolean added = false; + for (Entry e : c) { + if (add(e)) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } +} \ No newline at end of file diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/LongAdder.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/LongAdder.java new file mode 100644 index 0000000..e7a1c5f --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/LongAdder.java @@ -0,0 +1,204 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.9 version. + +package org.jruby.ext.thread_safe.jsr166e.nounsafe; + +import java.util.concurrent.atomic.AtomicLong; +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

    This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

    This class extends {@link Number}, but does not define + * methods such as {@code hashCode} and {@code compareTo} because + * instances are expected to be mutated, and so are not useful as + * collection keys. + * + *

    jsr166e note: This class is targeted to be placed in + * java.util.concurrent.atomic. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Version of plus for use in retryUpdate + */ + final long fn(long v, long x) { return v + x; } + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; HashCode hc; Cell a; int n; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + int h = (hc = threadHashCode.get()).code; + if (as == null || (n = as.length) < 1 || + (a = as[(n - 1) & h]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + retryUpdate(x, hc, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot: Invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + long sum = base; + Cell[] as = cells; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + internalReset(0L); + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + long sum = base; + Cell[] as = cells; + base = 0L; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + busy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/Striped64.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/Striped64.java new file mode 100644 index 0000000..ee69567 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/Striped64.java @@ -0,0 +1,291 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.5 version. + +package org.jruby.ext.thread_safe.jsr166e.nounsafe; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("busy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock: When the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * Per-thread hash codes are initialized to random values. + * Contention and/or table collisions are indicated by failed + * CASes when performing an update operation (see method + * retryUpdate). Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + + static AtomicLongFieldUpdater VALUE_UPDATER = AtomicLongFieldUpdater.newUpdater(Cell.class, "value"); + + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return VALUE_UPDATER.compareAndSet(this, cmp, val); + } + + } + + /** + * Holder for the thread-local hash code. The code is initially + * random, but may be set to a different value upon collisions. + */ + static final class HashCode { + static final Random rng = new Random(); + int code; + HashCode() { + int h = rng.nextInt(); // Avoid zero to allow xorShift rehash + code = (h == 0) ? 1 : h; + } + } + + /** + * The corresponding ThreadLocal class + */ + static final class ThreadHashCode extends ThreadLocal { + public HashCode initialValue() { return new HashCode(); } + } + + /** + * Static per-thread hash codes. Shared across all instances to + * reduce ThreadLocal pollution and because adjustments due to + * collisions in one table are likely to be appropriate for + * others. + */ + static final ThreadHashCode threadHashCode = new ThreadHashCode(); + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int busy; + + AtomicLongFieldUpdater BASE_UPDATER = AtomicLongFieldUpdater.newUpdater(Striped64.class, "base"); + AtomicIntegerFieldUpdater BUSY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Striped64.class, "busy"); + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return BASE_UPDATER.compareAndSet(this, cmp, val); + } + + /** + * CASes the busy field from 0 to 1 to acquire lock. + */ + final boolean casBusy() { + return BUSY_UPDATER.compareAndSet(this, 0, 1); + } + + /** + * Computes the function of current and new value. Subclasses + * should open-code this update function for most uses, but the + * virtualized form is needed within retryUpdate. + * + * @param currentValue the current value (of either base or a cell) + * @param newValue the argument from a user update call + * @return result of the update function + */ + abstract long fn(long currentValue, long newValue); + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param hc the hash code holder + * @param wasUncontended false if CAS failed before call + */ + final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { + int h = hc.code; + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (busy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (busy == 0 && casBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + busy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, fn(v, x))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (busy == 0 && casBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + busy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h ^= h << 13; // Rehash + h ^= h >>> 17; + h ^= h << 5; + } + else if (busy == 0 && cells == as && casBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + busy = 0; + } + if (init) + break; + } + else if (casBase(v = base, fn(v, x))) + break; // Fall back on using base + } + hc.code = h; // Record index for next time + } + + + /** + * Sets base and all cells to the given value. + */ + final void internalReset(long initialValue) { + Cell[] as = cells; + base = initialValue; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + a.value = initialValue; + } + } + } +} \ No newline at end of file diff --git a/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166y/ThreadLocalRandom.java b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166y/ThreadLocalRandom.java new file mode 100644 index 0000000..81ba441 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/org/jruby/ext/thread_safe/jsr166y/ThreadLocalRandom.java @@ -0,0 +1,199 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.16 version + +package org.jruby.ext.thread_safe.jsr166y; + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

    Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

    This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit calls to setSeed to succeed only + * while executing the Random constructor. We can't allow others + * since it would cause setting seed in one part of a program to + * unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal localRandom = + new ThreadLocal() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + */ + ThreadLocalRandom() { + super(); + initialized = true; + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +} diff --git a/.gems/gems/thread_safe-0.3.4/ext/thread_safe/JrubyCacheBackendService.java b/.gems/gems/thread_safe-0.3.4/ext/thread_safe/JrubyCacheBackendService.java new file mode 100644 index 0000000..2c5bcea --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/ext/thread_safe/JrubyCacheBackendService.java @@ -0,0 +1,15 @@ +package thread_safe; + +import java.io.IOException; + +import org.jruby.Ruby; +import org.jruby.ext.thread_safe.JRubyCacheBackendLibrary; +import org.jruby.runtime.load.BasicLibraryService; + +// can't name this JRubyCacheBackendService or else JRuby doesn't pick this up +public class JrubyCacheBackendService implements BasicLibraryService { + public boolean basicLoad(final Ruby runtime) throws IOException { + new JRubyCacheBackendLibrary().load(runtime, false); + return true; + } +} diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe.rb new file mode 100644 index 0000000..5b8fb27 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe.rb @@ -0,0 +1,65 @@ +require 'thread_safe/version' +require 'thread_safe/synchronized_delegator' + +module ThreadSafe + autoload :Cache, 'thread_safe/cache' + autoload :Util, 'thread_safe/util' + + # Various classes within allows for +nil+ values to be stored, so a special +NULL+ token is required to indicate the "nil-ness". + NULL = Object.new + + if defined?(JRUBY_VERSION) + require 'jruby/synchronized' + + # A thread-safe subclass of Array. This version locks + # against the object itself for every method call, + # ensuring only one thread can be reading or writing + # at a time. This includes iteration methods like + # #each. + class Array < ::Array + include JRuby::Synchronized + end + + # A thread-safe subclass of Hash. This version locks + # against the object itself for every method call, + # ensuring only one thread can be reading or writing + # at a time. This includes iteration methods like + # #each. + class Hash < ::Hash + include JRuby::Synchronized + end + elsif !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby' + # Because MRI never runs code in parallel, the existing + # non-thread-safe structures should usually work fine. + Array = ::Array + Hash = ::Hash + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' + require 'monitor' + + class Hash < ::Hash; end + class Array < ::Array; end + + [Hash, Array].each do |klass| + klass.class_eval do + private + def _mon_initialize + @_monitor = Monitor.new unless @_monitor # avoid double initialisation + end + + def self.allocate + obj = super + obj.send(:_mon_initialize) + obj + end + end + + klass.superclass.instance_methods(false).each do |method| + klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{method}(*args) + @_monitor.synchronize { super } + end + RUBY_EVAL + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/atomic_reference_cache_backend.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/atomic_reference_cache_backend.rb new file mode 100644 index 0000000..0e4af2d --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/atomic_reference_cache_backend.rb @@ -0,0 +1,922 @@ +module ThreadSafe + # A Ruby port of the Doug Lea's jsr166e.ConcurrentHashMapV8 class version 1.59 available in public domain. + # Original source code available here: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/ConcurrentHashMapV8.java?revision=1.59 + # + # The Ruby port skips out the +TreeBin+ (red-black trees for use in bins + # whose size exceeds a threshold). + # + # A hash table supporting full concurrency of retrievals and + # high expected concurrency for updates. However, even though all + # operations are thread-safe, retrieval operations do _not_ entail locking, + # and there is _not_ any support for locking the entire table + # in a way that prevents all access. + # + # Retrieval operations generally do not block, so may overlap with + # update operations. Retrievals reflect the results of the most + # recently _completed_ update operations holding upon their + # onset. (More formally, an update operation for a given key bears a + # _happens-before_ relation with any (non +nil+) retrieval for + # that key reporting the updated value.) For aggregate operations + # such as +clear()+, concurrent retrievals may reflect insertion or removal + # of only some entries. Similarly, the +each_pair+ iterator yields elements + # reflecting the state of the hash table at some point at or since + # the start of the +each_pair+. Bear in mind that the results of + # aggregate status methods including +size()+ and +empty?+} are typically + # useful only when a map is not undergoing concurrent updates in other + # threads. Otherwise the results of these methods reflect transient + # states that may be adequate for monitoring or estimation purposes, but not + # for program control. + # + # The table is dynamically expanded when there are too many + # collisions (i.e., keys that have distinct hash codes but fall into + # the same slot modulo the table size), with the expected average + # effect of maintaining roughly two bins per mapping (corresponding + # to a 0.75 load factor threshold for resizing). There may be much + # variance around this average as mappings are added and removed, but + # overall, this maintains a commonly accepted time/space tradeoff for + # hash tables. However, resizing this or any other kind of hash + # table may be a relatively slow operation. When possible, it is a + # good idea to provide a size estimate as an optional :initial_capacity + # initializer argument. An additional optional :load_factor constructor + # argument provides a further means of customizing initial table capacity + # by specifying the table density to be used in calculating the amount of + # space to allocate for the given number of elements. Note that using + # many keys with exactly the same +hash+ is a sure way to slow down + # performance of any hash table. + # + # == Design overview + # + # The primary design goal of this hash table is to maintain + # concurrent readability (typically method +[]+, but also + # iteration and related methods) while minimizing update + # contention. Secondary goals are to keep space consumption about + # the same or better than plain +Hash+, and to support high + # initial insertion rates on an empty table by many threads. + # + # Each key-value mapping is held in a +Node+. The validation-based + # approach explained below leads to a lot of code sprawl because + # retry-control precludes factoring into smaller methods. + # + # The table is lazily initialized to a power-of-two size upon the + # first insertion. Each bin in the table normally contains a + # list of +Node+s (most often, the list has only zero or one +Node+). + # Table accesses require volatile/atomic reads, writes, and + # CASes. The lists of nodes within bins are always accurately traversable + # under volatile reads, so long as lookups check hash code + # and non-nullness of value before checking key equality. + # + # We use the top two bits of +Node+ hash fields for control + # purposes -- they are available anyway because of addressing + # constraints. As explained further below, these top bits are + # used as follows: + # 00 - Normal + # 01 - Locked + # 11 - Locked and may have a thread waiting for lock + # 10 - +Node+ is a forwarding node + # + # The lower 28 bits of each +Node+'s hash field contain a + # the key's hash code, except for forwarding nodes, for which + # the lower bits are zero (and so always have hash field == +MOVED+). + # + # Insertion (via +[]=+ or its variants) of the first node in an + # empty bin is performed by just CASing it to the bin. This is + # by far the most common case for put operations under most + # key/hash distributions. Other update operations (insert, + # delete, and replace) require locks. We do not want to waste + # the space required to associate a distinct lock object with + # each bin, so instead use the first node of a bin list itself as + # a lock. Blocking support for these locks relies +Util::CheapLockable. + # However, we also need a +try_lock+ construction, so we overlay + # these by using bits of the +Node+ hash field for lock control (see above), + # and so normally use builtin monitors only for blocking and signalling using + # +cheap_wait+/+cheap_broadcast+ constructions. See +Node#try_await_lock+. + # + # Using the first node of a list as a lock does not by itself + # suffice though: When a node is locked, any update must first + # validate that it is still the first node after locking it, and + # retry if not. Because new nodes are always appended to lists, + # once a node is first in a bin, it remains first until deleted + # or the bin becomes invalidated (upon resizing). However, + # operations that only conditionally update may inspect nodes + # until the point of update. This is a converse of sorts to the + # lazy locking technique described by Herlihy & Shavit. + # + # The main disadvantage of per-bin locks is that other update + # operations on other nodes in a bin list protected by the same + # lock can stall, for example when user +eql?+ or mapping + # functions take a long time. However, statistically, under + # random hash codes, this is not a common problem. Ideally, the + # frequency of nodes in bins follows a Poisson distribution + # (http://en.wikipedia.org/wiki/Poisson_distribution) with a + # parameter of about 0.5 on average, given the resizing threshold + # of 0.75, although with a large variance because of resizing + # granularity. Ignoring variance, the expected occurrences of + # list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + # first values are: + # + # 0: 0.60653066 + # 1: 0.30326533 + # 2: 0.07581633 + # 3: 0.01263606 + # 4: 0.00157952 + # 5: 0.00015795 + # 6: 0.00001316 + # 7: 0.00000094 + # 8: 0.00000006 + # more: less than 1 in ten million + # + # Lock contention probability for two threads accessing distinct + # elements is roughly 1 / (8 * #elements) under random hashes. + # + # The table is resized when occupancy exceeds a percentage + # threshold (nominally, 0.75, but see below). Only a single + # thread performs the resize (using field +size_control+, to arrange + # exclusion), but the table otherwise remains usable for reads + # and updates. Resizing proceeds by transferring bins, one by + # one, from the table to the next table. Because we are using + # power-of-two expansion, the elements from each bin must either + # stay at same index, or move with a power of two offset. We + # eliminate unnecessary node creation by catching cases where old + # nodes can be reused because their next fields won't change. On + # average, only about one-sixth of them need cloning when a table + # doubles. The nodes they replace will be garbage collectable as + # soon as they are no longer referenced by any reader thread that + # may be in the midst of concurrently traversing table. Upon + # transfer, the old table bin contains only a special forwarding + # node (with hash field +MOVED+) that contains the next table as + # its key. On encountering a forwarding node, access and update + # operations restart, using the new table. + # + # Each bin transfer requires its bin lock. However, unlike other + # cases, a transfer can skip a bin if it fails to acquire its + # lock, and revisit it later. Method +rebuild+ maintains a buffer of + # TRANSFER_BUFFER_SIZE bins that have been skipped because of failure + # to acquire a lock, and blocks only if none are available + # (i.e., only very rarely). The transfer operation must also ensure + # that all accessible bins in both the old and new table are usable by + # any traversal. When there are no lock acquisition failures, this is + # arranged simply by proceeding from the last bin (+table.size - 1+) up + # towards the first. Upon seeing a forwarding node, traversals arrange + # to move to the new table without revisiting nodes. However, when any + # node is skipped during a transfer, all earlier table bins may have + # become visible, so are initialized with a reverse-forwarding node back + # to the old table until the new ones are established. (This + # sometimes requires transiently locking a forwarding node, which + # is possible under the above encoding.) These more expensive + # mechanics trigger only when necessary. + # + # The traversal scheme also applies to partial traversals of + # ranges of bins (via an alternate Traverser constructor) + # to support partitioned aggregate operations. Also, read-only + # operations give up if ever forwarded to a null table, which + # provides support for shutdown-style clearing, which is also not + # currently implemented. + # + # Lazy table initialization minimizes footprint until first use. + # + # The element count is maintained using a +ThreadSafe::Util::Adder+, + # which avoids contention on updates but can encounter cache thrashing + # if read too frequently during concurrent access. To avoid reading so + # often, resizing is attempted either when a bin lock is + # contended, or upon adding to a bin already holding two or more + # nodes (checked before adding in the +x_if_absent+ methods, after + # adding in others). Under uniform hash distributions, the + # probability of this occurring at threshold is around 13%, + # meaning that only about 1 in 8 puts check threshold (and after + # resizing, many fewer do so). But this approximation has high + # variance for small table sizes, so we check on any collision + # for sizes <= 64. The bulk putAll operation further reduces + # contention by only committing count updates upon these size + # checks. + class AtomicReferenceCacheBackend + class Table < Util::PowerOfTwoTuple + def cas_new_node(i, hash, key, value) + cas(i, nil, Node.new(hash, key, value)) + end + + def try_to_cas_in_computed(i, hash, key) + succeeded = false + new_value = nil + new_node = Node.new(locked_hash = hash | LOCKED, key, NULL) + if cas(i, nil, new_node) + begin + if NULL == (new_value = yield(NULL)) + was_null = true + else + new_node.value = new_value + end + succeeded = true + ensure + volatile_set(i, nil) if !succeeded || was_null + new_node.unlock_via_hash(locked_hash, hash) + end + end + return succeeded, new_value + end + + def try_lock_via_hash(i, node, node_hash) + node.try_lock_via_hash(node_hash) do + yield if volatile_get(i) == node + end + end + + def delete_node_at(i, node, predecessor_node) + if predecessor_node + predecessor_node.next = node.next + else + volatile_set(i, node.next) + end + end + end + + # Key-value entry. Nodes with a hash field of +MOVED+ are special, + # and do not contain user keys or values. Otherwise, keys are never +nil+, + # and +NULL+ +value+ fields indicate that a node is in the process + # of being deleted or created. For purposes of read-only access, a key may be read + # before a value, but can only be used after checking value to be +!= NULL+. + class Node + extend Util::Volatile + attr_volatile :hash, :value, :next + + include Util::CheapLockable + + bit_shift = Util::FIXNUM_BIT_SIZE - 2 # need 2 bits for ourselves + # Encodings for special uses of Node hash fields. See above for explanation. + MOVED = ('10' << ('0' * bit_shift)).to_i(2) # hash field for forwarding nodes + LOCKED = ('01' << ('0' * bit_shift)).to_i(2) # set/tested only as a bit + WAITING = ('11' << ('0' * bit_shift)).to_i(2) # both bits set/tested together + HASH_BITS = ('00' << ('1' * bit_shift)).to_i(2) # usable bits of normal node hash + + SPIN_LOCK_ATTEMPTS = Util::CPU_COUNT > 1 ? Util::CPU_COUNT * 2 : 0 + + attr_reader :key + + def initialize(hash, key, value, next_node = nil) + super() + @key = key + self.lazy_set_hash(hash) + self.lazy_set_value(value) + self.next = next_node + end + + # Spins a while if +LOCKED+ bit set and this node is the first + # of its bin, and then sets +WAITING+ bits on hash field and + # blocks (once) if they are still set. It is OK for this + # method to return even if lock is not available upon exit, + # which enables these simple single-wait mechanics. + # + # The corresponding signalling operation is performed within + # callers: Upon detecting that +WAITING+ has been set when + # unlocking lock (via a failed CAS from non-waiting +LOCKED+ + # state), unlockers acquire the +cheap_synchronize+ lock and + # perform a +cheap_broadcast+. + def try_await_lock(table, i) + if table && i >= 0 && i < table.size # bounds check, TODO: why are we bounds checking? + spins = SPIN_LOCK_ATTEMPTS + randomizer = base_randomizer = Util::XorShiftRandom.get + while equal?(table.volatile_get(i)) && self.class.locked_hash?(my_hash = hash) + if spins >= 0 + if (randomizer = (randomizer >> 1)).even? # spin at random + if (spins -= 1) == 0 + Thread.pass # yield before blocking + else + randomizer = base_randomizer = Util::XorShiftRandom.xorshift(base_randomizer) if randomizer.zero? + end + end + elsif cas_hash(my_hash, my_hash | WAITING) + force_aquire_lock(table, i) + break + end + end + end + end + + def key?(key) + @key.eql?(key) + end + + def matches?(key, hash) + pure_hash == hash && key?(key) + end + + def pure_hash + hash & HASH_BITS + end + + def try_lock_via_hash(node_hash = hash) + if cas_hash(node_hash, locked_hash = node_hash | LOCKED) + begin + yield + ensure + unlock_via_hash(locked_hash, node_hash) + end + end + end + + def locked? + self.class.locked_hash?(hash) + end + + def unlock_via_hash(locked_hash, node_hash) + unless cas_hash(locked_hash, node_hash) + self.hash = node_hash + cheap_synchronize { cheap_broadcast } + end + end + + private + def force_aquire_lock(table, i) + cheap_synchronize do + if equal?(table.volatile_get(i)) && (hash & WAITING) == WAITING + cheap_wait + else + cheap_broadcast # possibly won race vs signaller + end + end + end + + class << self + def locked_hash?(hash) + (hash & LOCKED) != 0 + end + end + end + + # shorthands + MOVED = Node::MOVED + LOCKED = Node::LOCKED + WAITING = Node::WAITING + HASH_BITS = Node::HASH_BITS + + NOW_RESIZING = -1 + DEFAULT_CAPACITY = 16 + MAX_CAPACITY = Util::MAX_INT + + # The buffer size for skipped bins during transfers. The + # value is arbitrary but should be large enough to avoid + # most locking stalls during resizes. + TRANSFER_BUFFER_SIZE = 32 + + extend Util::Volatile + attr_volatile :table, # The array of bins. Lazily initialized upon first insertion. Size is always a power of two. + + # Table initialization and resizing control. When negative, the + # table is being initialized or resized. Otherwise, when table is + # null, holds the initial table size to use upon creation, or 0 + # for default. After initialization, holds the next element count + # value upon which to resize the table. + :size_control + + def initialize(options = nil) + super() + @counter = Util::Adder.new + initial_capacity = options && options[:initial_capacity] || DEFAULT_CAPACITY + self.size_control = (capacity = table_size_for(initial_capacity)) > MAX_CAPACITY ? MAX_CAPACITY : capacity + end + + def get_or_default(key, else_value = nil) + hash = key_hash(key) + current_table = table + while current_table + node = current_table.volatile_get_by_hash(hash) + current_table = + while node + if (node_hash = node.hash) == MOVED + break node.key + elsif (node_hash & HASH_BITS) == hash && node.key?(key) && NULL != (value = node.value) + return value + end + node = node.next + end + end + else_value + end + + def [](key) + get_or_default(key) + end + + def key?(key) + get_or_default(key, NULL) != NULL + end + + def []=(key, value) + get_and_set(key, value) + value + end + + def compute_if_absent(key) + hash = key_hash(key) + current_table = table || initialize_table + while true + if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) + succeeded, new_value = current_table.try_to_cas_in_computed(i, hash, key) { yield } + if succeeded + increment_size + return new_value + end + elsif (node_hash = node.hash) == MOVED + current_table = node.key + elsif NULL != (current_value = find_value_in_node_list(node, key, hash, node_hash & HASH_BITS)) + return current_value + elsif Node.locked_hash?(node_hash) + try_await_lock(current_table, i, node) + else + succeeded, value = attempt_internal_compute_if_absent(key, hash, current_table, i, node, node_hash) { yield } + return value if succeeded + end + end + end + + def compute_if_present(key) + new_value = nil + internal_replace(key) do |old_value| + if (new_value = yield(NULL == old_value ? nil : old_value)).nil? + NULL + else + new_value + end + end + new_value + end + + def compute(key) + internal_compute(key) do |old_value| + if (new_value = yield(NULL == old_value ? nil : old_value)).nil? + NULL + else + new_value + end + end + end + + def merge_pair(key, value) + internal_compute(key) do |old_value| + if NULL == old_value || !(value = yield(old_value)).nil? + value + else + NULL + end + end + end + + def replace_pair(key, old_value, new_value) + NULL != internal_replace(key, old_value) { new_value } + end + + def replace_if_exists(key, new_value) + if (result = internal_replace(key) { new_value }) && NULL != result + result + end + end + + def get_and_set(key, value) # internalPut in the original CHMV8 + hash = key_hash(key) + current_table = table || initialize_table + while true + if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) + if current_table.cas_new_node(i, hash, key, value) + increment_size + break + end + elsif (node_hash = node.hash) == MOVED + current_table = node.key + elsif Node.locked_hash?(node_hash) + try_await_lock(current_table, i, node) + else + succeeded, old_value = attempt_get_and_set(key, value, hash, current_table, i, node, node_hash) + break old_value if succeeded + end + end + end + + def delete(key) + replace_if_exists(key, NULL) + end + + def delete_pair(key, value) + result = internal_replace(key, value) { NULL } + if result && NULL != result + !!result + else + false + end + end + + def each_pair + return self unless current_table = table + current_table_size = base_size = current_table.size + i = base_index = 0 + while base_index < base_size + if node = current_table.volatile_get(i) + if node.hash == MOVED + current_table = node.key + current_table_size = current_table.size + else + begin + if NULL != (value = node.value) # skip deleted or special nodes + yield node.key, value + end + end while node = node.next + end + end + + if (i_with_base = i + base_size) < current_table_size + i = i_with_base # visit upper slots if present + else + i = base_index += 1 + end + end + self + end + + def size + (sum = @counter.sum) < 0 ? 0 : sum # ignore transient negative values + end + + def empty? + size == 0 + end + + # Implementation for clear. Steps through each bin, removing all nodes. + def clear + return self unless current_table = table + current_table_size = current_table.size + deleted_count = i = 0 + while i < current_table_size + if !(node = current_table.volatile_get(i)) + i += 1 + elsif (node_hash = node.hash) == MOVED + current_table = node.key + current_table_size = current_table.size + elsif Node.locked_hash?(node_hash) + decrement_size(deleted_count) # opportunistically update count + deleted_count = 0 + node.try_await_lock(current_table, i) + else + current_table.try_lock_via_hash(i, node, node_hash) do + begin + deleted_count += 1 if NULL != node.value # recheck under lock + node.value = nil + end while node = node.next + current_table.volatile_set(i, nil) + i += 1 + end + end + end + decrement_size(deleted_count) + self + end + + private + # Internal versions of the insertion methods, each a + # little more complicated than the last. All have + # the same basic structure: + # 1. If table uninitialized, create + # 2. If bin empty, try to CAS new node + # 3. If bin stale, use new table + # 4. Lock and validate; if valid, scan and add or update + # + # The others interweave other checks and/or alternative actions: + # * Plain +get_and_set+ checks for and performs resize after insertion. + # * compute_if_absent prescans for mapping without lock (and fails to add + # if present), which also makes pre-emptive resize checks worthwhile. + # + # Someday when details settle down a bit more, it might be worth + # some factoring to reduce sprawl. + def internal_replace(key, expected_old_value = NULL, &block) + hash = key_hash(key) + current_table = table + while current_table + if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) + break + elsif (node_hash = node.hash) == MOVED + current_table = node.key + elsif (node_hash & HASH_BITS) != hash && !node.next # precheck + break # rules out possible existence + elsif Node.locked_hash?(node_hash) + try_await_lock(current_table, i, node) + else + succeeded, old_value = attempt_internal_replace(key, expected_old_value, hash, current_table, i, node, node_hash, &block) + return old_value if succeeded + end + end + NULL + end + + def attempt_internal_replace(key, expected_old_value, hash, current_table, i, node, node_hash) + current_table.try_lock_via_hash(i, node, node_hash) do + predecessor_node = nil + old_value = NULL + begin + if node.matches?(key, hash) && NULL != (current_value = node.value) + if NULL == expected_old_value || expected_old_value == current_value # NULL == expected_old_value means whatever value + old_value = current_value + if NULL == (node.value = yield(old_value)) + current_table.delete_node_at(i, node, predecessor_node) + decrement_size + end + end + break + end + + predecessor_node = node + end while node = node.next + + return true, old_value + end + end + + def find_value_in_node_list(node, key, hash, pure_hash) + do_check_for_resize = false + while true + if pure_hash == hash && node.key?(key) && NULL != (value = node.value) + return value + elsif node = node.next + do_check_for_resize = true # at least 2 nodes -> check for resize + pure_hash = node.pure_hash + else + return NULL + end + end + ensure + check_for_resize if do_check_for_resize + end + + def internal_compute(key, &block) + hash = key_hash(key) + current_table = table || initialize_table + while true + if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) + succeeded, new_value = current_table.try_to_cas_in_computed(i, hash, key, &block) + if succeeded + if NULL == new_value + break nil + else + increment_size + break new_value + end + end + elsif (node_hash = node.hash) == MOVED + current_table = node.key + elsif Node.locked_hash?(node_hash) + try_await_lock(current_table, i, node) + else + succeeded, new_value = attempt_compute(key, hash, current_table, i, node, node_hash, &block) + break new_value if succeeded + end + end + end + + def attempt_internal_compute_if_absent(key, hash, current_table, i, node, node_hash) + added = false + current_table.try_lock_via_hash(i, node, node_hash) do + while true + if node.matches?(key, hash) && NULL != (value = node.value) + return true, value + end + last = node + unless node = node.next + last.next = Node.new(hash, key, value = yield) + added = true + increment_size + return true, value + end + end + end + ensure + check_for_resize if added + end + + def attempt_compute(key, hash, current_table, i, node, node_hash) + added = false + current_table.try_lock_via_hash(i, node, node_hash) do + predecessor_node = nil + while true + if node.matches?(key, hash) && NULL != (value = node.value) + if NULL == (node.value = value = yield(value)) + current_table.delete_node_at(i, node, predecessor_node) + decrement_size + value = nil + end + return true, value + end + predecessor_node = node + unless node = node.next + if NULL == (value = yield(NULL)) + value = nil + else + predecessor_node.next = Node.new(hash, key, value) + added = true + increment_size + end + return true, value + end + end + end + ensure + check_for_resize if added + end + + def attempt_get_and_set(key, value, hash, current_table, i, node, node_hash) + node_nesting = nil + current_table.try_lock_via_hash(i, node, node_hash) do + node_nesting = 1 + old_value = nil + found_old_value = false + while node + if node.matches?(key, hash) && NULL != (old_value = node.value) + found_old_value = true + node.value = value + break + end + last = node + unless node = node.next + last.next = Node.new(hash, key, value) + break + end + node_nesting += 1 + end + + return true, old_value if found_old_value + increment_size + true + end + ensure + check_for_resize if node_nesting && (node_nesting > 1 || current_table.size <= 64) + end + + def initialize_copy(other) + super + @counter = Util::Adder.new + self.table = nil + self.size_control = (other_table = other.table) ? other_table.size : DEFAULT_CAPACITY + self + end + + def try_await_lock(current_table, i, node) + check_for_resize # try resizing if can't get lock + node.try_await_lock(current_table, i) + end + + def key_hash(key) + key.hash & HASH_BITS + end + + # Returns a power of two table size for the given desired capacity. + def table_size_for(entry_count) + size = 2 + size <<= 1 while size < entry_count + size + end + + # Initializes table, using the size recorded in +size_control+. + def initialize_table + until current_table ||= table + if (size_ctrl = size_control) == NOW_RESIZING + Thread.pass # lost initialization race; just spin + else + try_in_resize_lock(current_table, size_ctrl) do + initial_size = size_ctrl > 0 ? size_ctrl : DEFAULT_CAPACITY + current_table = self.table = Table.new(initial_size) + initial_size - (initial_size >> 2) # 75% load factor + end + end + end + current_table + end + + # If table is too small and not already resizing, creates next + # table and transfers bins. Rechecks occupancy after a transfer + # to see if another resize is already needed because resizings + # are lagging additions. + def check_for_resize + while (current_table = table) && MAX_CAPACITY > (table_size = current_table.size) && NOW_RESIZING != (size_ctrl = size_control) && size_ctrl < @counter.sum + try_in_resize_lock(current_table, size_ctrl) do + self.table = rebuild(current_table) + (table_size << 1) - (table_size >> 1) # 75% load factor + end + end + end + + def try_in_resize_lock(current_table, size_ctrl) + if cas_size_control(size_ctrl, NOW_RESIZING) + begin + if current_table == table # recheck under lock + size_ctrl = yield # get new size_control + end + ensure + self.size_control = size_ctrl + end + end + end + + # Moves and/or copies the nodes in each bin to new table. See above for explanation. + def rebuild(table) + old_table_size = table.size + new_table = table.next_in_size_table + # puts "#{old_table_size} -> #{new_table.size}" + forwarder = Node.new(MOVED, new_table, NULL) + rev_forwarder = nil + locked_indexes = nil # holds bins to revisit; nil until needed + locked_arr_idx = 0 + bin = old_table_size - 1 + i = bin + while true + if !(node = table.volatile_get(i)) + # no lock needed (or available) if bin >= 0, because we're not popping values from locked_indexes until we've run through the whole table + redo unless (bin >= 0 ? table.cas(i, nil, forwarder) : lock_and_clean_up_reverse_forwarders(table, old_table_size, new_table, i, forwarder)) + elsif Node.locked_hash?(node_hash = node.hash) + locked_indexes ||= Array.new + if bin < 0 && locked_arr_idx > 0 + locked_arr_idx -= 1 + i, locked_indexes[locked_arr_idx] = locked_indexes[locked_arr_idx], i # swap with another bin + redo + end + if bin < 0 || locked_indexes.size >= TRANSFER_BUFFER_SIZE + node.try_await_lock(table, i) # no other options -- block + redo + end + rev_forwarder ||= Node.new(MOVED, table, NULL) + redo unless table.volatile_get(i) == node && node.locked? # recheck before adding to list + locked_indexes << i + new_table.volatile_set(i, rev_forwarder) + new_table.volatile_set(i + old_table_size, rev_forwarder) + else + redo unless split_old_bin(table, new_table, i, node, node_hash, forwarder) + end + + if bin > 0 + i = (bin -= 1) + elsif locked_indexes && !locked_indexes.empty? + bin = -1 + i = locked_indexes.pop + locked_arr_idx = locked_indexes.size - 1 + else + return new_table + end + end + end + + def lock_and_clean_up_reverse_forwarders(old_table, old_table_size, new_table, i, forwarder) + # transiently use a locked forwarding node + locked_forwarder = Node.new(moved_locked_hash = MOVED | LOCKED, new_table, NULL) + if old_table.cas(i, nil, locked_forwarder) + new_table.volatile_set(i, nil) # kill the potential reverse forwarders + new_table.volatile_set(i + old_table_size, nil) # kill the potential reverse forwarders + old_table.volatile_set(i, forwarder) + locked_forwarder.unlock_via_hash(moved_locked_hash, MOVED) + true + end + end + + # Splits a normal bin with list headed by e into lo and hi parts; installs in given table. + def split_old_bin(table, new_table, i, node, node_hash, forwarder) + table.try_lock_via_hash(i, node, node_hash) do + split_bin(new_table, i, node, node_hash) + table.volatile_set(i, forwarder) + end + end + + def split_bin(new_table, i, node, node_hash) + bit = new_table.size >> 1 # bit to split on + run_bit = node_hash & bit + last_run = nil + low = nil + high = nil + current_node = node + # this optimises for the lowest amount of volatile writes and objects created + while current_node = current_node.next + unless (b = current_node.hash & bit) == run_bit + run_bit = b + last_run = current_node + end + end + if run_bit == 0 + low = last_run + else + high = last_run + end + current_node = node + until current_node == last_run + pure_hash = current_node.pure_hash + if (pure_hash & bit) == 0 + low = Node.new(pure_hash, current_node.key, current_node.value, low) + else + high = Node.new(pure_hash, current_node.key, current_node.value, high) + end + current_node = current_node.next + end + new_table.volatile_set(i, low) + new_table.volatile_set(i + bit, high) + end + + def increment_size + @counter.increment + end + + def decrement_size(by = 1) + @counter.add(-by) + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/cache.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/cache.rb new file mode 100644 index 0000000..2539941 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/cache.rb @@ -0,0 +1,163 @@ +require 'thread' + +module ThreadSafe + autoload :JRubyCacheBackend, 'thread_safe/jruby_cache_backend' + autoload :MriCacheBackend, 'thread_safe/mri_cache_backend' + autoload :NonConcurrentCacheBackend, 'thread_safe/non_concurrent_cache_backend' + autoload :AtomicReferenceCacheBackend, 'thread_safe/atomic_reference_cache_backend' + autoload :SynchronizedCacheBackend, 'thread_safe/synchronized_cache_backend' + + ConcurrentCacheBackend = if defined?(RUBY_ENGINE) + case RUBY_ENGINE + when 'jruby'; JRubyCacheBackend + when 'ruby'; MriCacheBackend + when 'rbx'; AtomicReferenceCacheBackend + else + warn 'ThreadSafe: unsupported Ruby engine, using a fully synchronized ThreadSafe::Cache implementation' if $VERBOSE + SynchronizedCacheBackend + end + else + MriCacheBackend + end + + class Cache < ConcurrentCacheBackend + KEY_ERROR = defined?(KeyError) ? KeyError : IndexError # there is no KeyError in 1.8 mode + + def initialize(options = nil, &block) + if options.kind_of?(::Hash) + validate_options_hash!(options) + else + options = nil + end + + super(options) + @default_proc = block + end + + def [](key) + if value = super # non-falsy value is an existing mapping, return it right away + value + # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call + # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value + # would be returned) + # note: nil == value check is not technically necessary + elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL)) + @default_proc.call(self, key) + else + value + end + end + + alias_method :get, :[] + alias_method :put, :[]= + + def fetch(key, default_value = NULL) + if NULL != (value = get_or_default(key, NULL)) + value + elsif block_given? + yield key + elsif NULL != default_value + default_value + else + raise_fetch_no_key + end + end + + def fetch_or_store(key, default_value = NULL) + fetch(key) do + put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value)) + end + end + + def put_if_absent(key, value) + computed = false + result = compute_if_absent(key) do + computed = true + value + end + computed ? nil : result + end unless method_defined?(:put_if_absent) + + def value?(value) + each_value do |v| + return true if value.equal?(v) + end + false + end unless method_defined?(:value?) + + def keys + arr = [] + each_pair {|k, v| arr << k} + arr + end unless method_defined?(:keys) + + def values + arr = [] + each_pair {|k, v| arr << v} + arr + end unless method_defined?(:values) + + def each_key + each_pair {|k, v| yield k} + end unless method_defined?(:each_key) + + def each_value + each_pair {|k, v| yield v} + end unless method_defined?(:each_value) + + def key(value) + each_pair {|k, v| return k if v == value} + nil + end unless method_defined?(:key) + alias_method :index, :key if RUBY_VERSION < '1.9' + + def empty? + each_pair {|k, v| return false} + true + end unless method_defined?(:empty?) + + def size + count = 0 + each_pair {|k, v| count += 1} + count + end unless method_defined?(:size) + + def marshal_dump + raise TypeError, "can't dump hash with default proc" if @default_proc + h = {} + each_pair {|k, v| h[k] = v} + h + end + + def marshal_load(hash) + initialize + populate_from(hash) + end + + undef :freeze + + private + def raise_fetch_no_key + raise KEY_ERROR, 'key not found' + end + + def initialize_copy(other) + super + populate_from(other) + end + + def populate_from(hash) + hash.each_pair {|k, v| self[k] = v} + self + end + + def validate_options_hash!(options) + if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Fixnum) || initial_capacity < 0) + raise ArgumentError, ":initial_capacity must be a positive Fixnum" + end + if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1) + raise ArgumentError, ":load_factor must be a number between 0 and 1" + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/mri_cache_backend.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/mri_cache_backend.rb new file mode 100644 index 0000000..8768297 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/mri_cache_backend.rb @@ -0,0 +1,62 @@ +module ThreadSafe + class MriCacheBackend < NonConcurrentCacheBackend + # We can get away with a single global write lock (instead of a per-instance one) because of the GVL/green threads. + # + # The previous implementation used `Thread.critical` on 1.8 MRI to implement the 4 composed atomic operations (`put_if_absent`, `replace_pair`, + # `replace_if_exists`, `delete_pair`) this however doesn't work for `compute_if_absent` because on 1.8 the Mutex class is itself implemented + # via `Thread.critical` and a call to `Mutex#lock` does not restore the previous `Thread.critical` value (thus any synchronisation clears the + # `Thread.critical` flag and we loose control). This poses a problem as the provided block might use synchronisation on its own. + # + # NOTE: a neat idea of writing a c-ext to manually perform atomic put_if_absent, while relying on Ruby not releasing a GVL while calling + # a c-ext will not work because of the potentially Ruby implemented `#hash` and `#eql?` key methods. + WRITE_LOCK = Mutex.new + + def []=(key, value) + WRITE_LOCK.synchronize { super } + end + + def compute_if_absent(key) + if stored_value = _get(key) # fast non-blocking path for the most likely case + stored_value + else + WRITE_LOCK.synchronize { super } + end + end + + def compute_if_present(key) + WRITE_LOCK.synchronize { super } + end + + def compute(key) + WRITE_LOCK.synchronize { super } + end + + def merge_pair(key, value) + WRITE_LOCK.synchronize { super } + end + + def replace_pair(key, old_value, new_value) + WRITE_LOCK.synchronize { super } + end + + def replace_if_exists(key, new_value) + WRITE_LOCK.synchronize { super } + end + + def get_and_set(key, value) + WRITE_LOCK.synchronize { super } + end + + def delete(key) + WRITE_LOCK.synchronize { super } + end + + def delete_pair(key, value) + WRITE_LOCK.synchronize { super } + end + + def clear + WRITE_LOCK.synchronize { super } + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/non_concurrent_cache_backend.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/non_concurrent_cache_backend.rb new file mode 100644 index 0000000..2ef86d8 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/non_concurrent_cache_backend.rb @@ -0,0 +1,133 @@ +module ThreadSafe + class NonConcurrentCacheBackend + # WARNING: all public methods of the class must operate on the @backend directly without calling each other. This is important + # because of the SynchronizedCacheBackend which uses a non-reentrant mutex for perfomance reasons. + def initialize(options = nil) + @backend = {} + end + + def [](key) + @backend[key] + end + + def []=(key, value) + @backend[key] = value + end + + def compute_if_absent(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) + stored_value + else + @backend[key] = yield + end + end + + def replace_pair(key, old_value, new_value) + if pair?(key, old_value) + @backend[key] = new_value + true + else + false + end + end + + def replace_if_exists(key, new_value) + if NULL != (stored_value = @backend.fetch(key, NULL)) + @backend[key] = new_value + stored_value + end + end + + def compute_if_present(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) + store_computed_value(key, yield(stored_value)) + end + end + + def compute(key) + store_computed_value(key, yield(@backend[key])) + end + + def merge_pair(key, value) + if NULL == (stored_value = @backend.fetch(key, NULL)) + @backend[key] = value + else + store_computed_value(key, yield(stored_value)) + end + end + + def get_and_set(key, value) + stored_value = @backend[key] + @backend[key] = value + stored_value + end + + def key?(key) + @backend.key?(key) + end + + def value?(value) + @backend.value?(value) + end + + def delete(key) + @backend.delete(key) + end + + def delete_pair(key, value) + if pair?(key, value) + @backend.delete(key) + true + else + false + end + end + + def clear + @backend.clear + self + end + + def each_pair + dupped_backend.each_pair do |k, v| + yield k, v + end + self + end + + def size + @backend.size + end + + def get_or_default(key, default_value) + @backend.fetch(key, default_value) + end + + alias_method :_get, :[] + alias_method :_set, :[]= + private :_get, :_set + private + def initialize_copy(other) + super + @backend = {} + self + end + + def dupped_backend + @backend.dup + end + + def pair?(key, expected_value) + NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value) + end + + def store_computed_value(key, new_value) + if new_value.nil? + @backend.delete(key) + nil + else + @backend[key] = new_value + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_cache_backend.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_cache_backend.rb new file mode 100644 index 0000000..37a897f --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_cache_backend.rb @@ -0,0 +1,76 @@ +module ThreadSafe + class SynchronizedCacheBackend < NonConcurrentCacheBackend + require 'mutex_m' + include Mutex_m + # WARNING: Mutex_m is a non-reentrant lock, so the synchronized methods are not allowed to call each other. + + def [](key) + synchronize { super } + end + + def []=(key, value) + synchronize { super } + end + + def compute_if_absent(key) + synchronize { super } + end + + def compute_if_present(key) + synchronize { super } + end + + def compute(key) + synchronize { super } + end + + def merge_pair(key, value) + synchronize { super } + end + + def replace_pair(key, old_value, new_value) + synchronize { super } + end + + def replace_if_exists(key, new_value) + synchronize { super } + end + + def get_and_set(key, value) + synchronize { super } + end + + def key?(key) + synchronize { super } + end + + def value?(value) + synchronize { super } + end + + def delete(key) + synchronize { super } + end + + def delete_pair(key, value) + synchronize { super } + end + + def clear + synchronize { super } + end + + def size + synchronize { super } + end + + def get_or_default(key, default_value) + synchronize { super } + end + + private + def dupped_backend + synchronize { super } + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_delegator.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_delegator.rb new file mode 100644 index 0000000..9e18a56 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/synchronized_delegator.rb @@ -0,0 +1,60 @@ +require 'delegate' +require 'monitor' + +# This class provides a trivial way to synchronize all calls to a given object +# by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls +# around the delegated `#send`. Example: +# +# array = [] # not thread-safe on many impls +# array = SynchronizedDelegator.new([]) # thread-safe +# +# A simple `Monitor` provides a very coarse-grained way to synchronize a given +# object, in that it will cause synchronization for methods that have no +# need for it, but this is a trivial way to get thread-safety where none may +# exist currently on some implementations. +# +# This class is currently being considered for inclusion into stdlib, via +# https://bugs.ruby-lang.org/issues/8556 +class SynchronizedDelegator < SimpleDelegator + def setup + @old_abort = Thread.abort_on_exception + Thread.abort_on_exception = true + end + + def teardown + Thread.abort_on_exception = @old_abort + end + + def initialize(obj) + __setobj__(obj) + @monitor = Monitor.new + end + + def method_missing(method, *args, &block) + monitor = @monitor + begin + monitor.enter + super + ensure + monitor.exit + end + end + + # Work-around for 1.8 std-lib not passing block around to delegate. + # @private + def method_missing(method, *args, &block) + monitor = @monitor + begin + monitor.enter + target = self.__getobj__ + if target.respond_to?(method) + target.__send__(method, *args, &block) + else + super(method, *args, &block) + end + ensure + monitor.exit + end + end if RUBY_VERSION[0, 3] == '1.8' + +end unless defined?(SynchronizedDelegator) diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util.rb new file mode 100644 index 0000000..bad4238 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util.rb @@ -0,0 +1,16 @@ +module ThreadSafe + module Util + FIXNUM_BIT_SIZE = (0.size * 8) - 2 + MAX_INT = (2 ** FIXNUM_BIT_SIZE) - 1 + CPU_COUNT = 16 # is there a way to determine this? + + autoload :AtomicReference, 'thread_safe/util/atomic_reference' + autoload :Adder, 'thread_safe/util/adder' + autoload :CheapLockable, 'thread_safe/util/cheap_lockable' + autoload :PowerOfTwoTuple, 'thread_safe/util/power_of_two_tuple' + autoload :Striped64, 'thread_safe/util/striped64' + autoload :Volatile, 'thread_safe/util/volatile' + autoload :VolatileTuple, 'thread_safe/util/volatile_tuple' + autoload :XorShiftRandom, 'thread_safe/util/xor_shift_random' + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/adder.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/adder.rb new file mode 100644 index 0000000..35d01ee --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/adder.rb @@ -0,0 +1,59 @@ +module ThreadSafe + module Util + # A Ruby port of the Doug Lea's jsr166e.LondAdder class version 1.8 available in public domain. + # Original source code available here: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8 + # + # One or more variables that together maintain an initially zero + # sum. When updates (method +add+) are contended across threads, + # the set of variables may grow dynamically to reduce contention. + # Method +sum+ returns the current total combined across the + # variables maintaining the sum. + # + # This class is usually preferable to single +Atomic+ reference when + # multiple threads update a common sum that is used for purposes such + # as collecting statistics, not for fine-grained synchronization + # control. Under low update contention, the two classes have similar + # characteristics. But under high contention, expected throughput of + # this class is significantly higher, at the expense of higher space + # consumption. + class Adder < Striped64 + # Adds the given value. + def add(x) + if (current_cells = cells) || !cas_base_computed {|current_base| current_base + x} + was_uncontended = true + hash = hash_code + unless current_cells && (cell = current_cells.volatile_get_by_hash(hash)) && (was_uncontended = cell.cas_computed {|current_value| current_value + x}) + retry_update(x, hash, was_uncontended) {|current_value| current_value + x} + end + end + end + + def increment + add(1) + end + + def decrement + add(-1) + end + + # Returns the current sum. The returned value is _NOT_ an + # atomic snapshot: Invocation in the absence of concurrent + # updates returns an accurate result, but concurrent updates that + # occur while the sum is being calculated might not be + # incorporated. + def sum + x = base + if current_cells = cells + current_cells.each do |cell| + x += cell.value if cell + end + end + x + end + + def reset + internal_reset(0) + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/atomic_reference.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/atomic_reference.rb new file mode 100644 index 0000000..4d01e9f --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/atomic_reference.rb @@ -0,0 +1,45 @@ +module ThreadSafe + module Util + AtomicReference = + if defined?(Rubinius::AtomicReference) + # An overhead-less atomic reference. + Rubinius::AtomicReference + else + begin + require 'atomic' + defined?(Atomic::InternalReference) ? Atomic::InternalReference : Atomic + rescue LoadError, NameError + require 'thread' # get Mutex on 1.8 + class FullLockingAtomicReference + def initialize(value = nil) + @___mutex = Mutex.new + @___value = value + end + + def get + @___mutex.synchronize { @___value } + end + alias_method :value, :get + + def set(new_value) + @___mutex.synchronize { @___value = new_value } + end + alias_method :value=, :set + + def compare_and_set(old_value, new_value) + return false unless @___mutex.try_lock + begin + return false unless @___value.equal? old_value + @___value = new_value + ensure + @___mutex.unlock + end + true + end + end + + FullLockingAtomicReference + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/cheap_lockable.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/cheap_lockable.rb new file mode 100644 index 0000000..b317ed2 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/cheap_lockable.rb @@ -0,0 +1,105 @@ +module ThreadSafe + module Util + # Provides a cheapest possible (mainly in terms of memory usage) +Mutex+ with the +ConditionVariable+ bundled in. + # + # Usage: + # class A + # include CheapLockable + # + # def do_exlusively + # cheap_synchronize { yield } + # end + # + # def wait_for_something + # cheap_synchronize do + # cheap_wait until resource_available? + # do_something + # cheap_broadcast # wake up others + # end + # end + # end + module CheapLockable + private + engine = defined?(RUBY_ENGINE) && RUBY_ENGINE + if engine == 'rbx' + # Making use of the Rubinius' ability to lock via object headers to avoid the overhead of the extra Mutex objects. + def cheap_synchronize + Rubinius.lock(self) + begin + yield + ensure + Rubinius.unlock(self) + end + end + + def cheap_wait + wchan = Rubinius::Channel.new + + begin + waiters = @waiters ||= [] + waiters.push wchan + Rubinius.unlock(self) + signaled = wchan.receive_timeout nil + ensure + Rubinius.lock(self) + + unless signaled or waiters.delete(wchan) + # we timed out, but got signaled afterwards (e.g. while waiting to + # acquire @lock), so pass that signal on to the next waiter + waiters.shift << true unless waiters.empty? + end + end + + self + end + + def cheap_broadcast + waiters = @waiters ||= [] + waiters.shift << true until waiters.empty? + self + end + elsif engine == 'jruby' + # Use Java's native synchronized (this) { wait(); notifyAll(); } to avoid the overhead of the extra Mutex objects + require 'jruby' + + def cheap_synchronize + JRuby.reference0(self).synchronized { yield } + end + + def cheap_wait + JRuby.reference0(self).wait + end + + def cheap_broadcast + JRuby.reference0(self).notify_all + end + else + require 'thread' + + extend Volatile + attr_volatile :mutex + + # Non-reentrant Mutex#syncrhonize + def cheap_synchronize + true until (my_mutex = mutex) || cas_mutex(nil, my_mutex = Mutex.new) + my_mutex.synchronize { yield } + end + + # Releases this object's +cheap_synchronize+ lock and goes to sleep waiting for other threads to +cheap_broadcast+, reacquires the lock on wakeup. + # Must only be called in +cheap_broadcast+'s block. + def cheap_wait + conditional_variable = @conditional_variable ||= ConditionVariable.new + conditional_variable.wait(mutex) + end + + # Wakes up all threads waiting for this object's +cheap_synchronize+ lock. + # Must only be called in +cheap_broadcast+'s block. + def cheap_broadcast + if conditional_variable = @conditional_variable + conditional_variable.broadcast + end + end + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/power_of_two_tuple.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/power_of_two_tuple.rb new file mode 100644 index 0000000..3e2d076 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/power_of_two_tuple.rb @@ -0,0 +1,26 @@ +module ThreadSafe + module Util + class PowerOfTwoTuple < VolatileTuple + def initialize(size) + raise ArgumentError, "size must be a power of 2 (#{size.inspect} provided)" unless size > 0 && size & (size - 1) == 0 + super(size) + end + + def hash_to_index(hash) + (size - 1) & hash + end + + def volatile_get_by_hash(hash) + volatile_get(hash_to_index(hash)) + end + + def volatile_set_by_hash(hash, value) + volatile_set(hash_to_index(hash), value) + end + + def next_in_size_table + self.class.new(size << 1) + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/striped64.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/striped64.rb new file mode 100644 index 0000000..5296204 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/striped64.rb @@ -0,0 +1,226 @@ +module ThreadSafe + module Util + # A Ruby port of the Doug Lea's jsr166e.Striped64 class version 1.6 available in public domain. + # Original source code available here: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.6 + # + # Class holding common representation and mechanics for classes supporting dynamic striping on 64bit values. + # + # This class maintains a lazily-initialized table of atomically + # updated variables, plus an extra +base+ field. The table size + # is a power of two. Indexing uses masked per-thread hash codes. + # Nearly all methods on this class are private, accessed directly + # by subclasses. + # + # Table entries are of class +Cell+; a variant of AtomicLong padded + # to reduce cache contention on most processors. Padding is + # overkill for most Atomics because they are usually irregularly + # scattered in memory and thus don't interfere much with each + # other. But Atomic objects residing in arrays will tend to be + # placed adjacent to each other, and so will most often share + # cache lines (with a huge negative performance impact) without + # this precaution. + # + # In part because +Cell+s are relatively large, we avoid creating + # them until they are needed. When there is no contention, all + # updates are made to the +base+ field. Upon first contention (a + # failed CAS on +base+ update), the table is initialized to size 2. + # The table size is doubled upon further contention until + # reaching the nearest power of two greater than or equal to the + # number of CPUS. Table slots remain empty (+nil+) until they are + # needed. + # + # A single spinlock (+busy+) is used for initializing and + # resizing the table, as well as populating slots with new +Cell+s. + # There is no need for a blocking lock: When the lock is not + # available, threads try other slots (or the base). During these + # retries, there is increased contention and reduced locality, + # which is still better than alternatives. + # + # Per-thread hash codes are initialized to random values. + # Contention and/or table collisions are indicated by failed + # CASes when performing an update operation (see method + # +retry_update+). Upon a collision, if the table size is less than + # the capacity, it is doubled in size unless some other thread + # holds the lock. If a hashed slot is empty, and lock is + # available, a new +Cell+ is created. Otherwise, if the slot + # exists, a CAS is tried. Retries proceed by "double hashing", + # using a secondary hash (XorShift) to try to find a + # free slot. + # + # The table size is capped because, when there are more threads + # than CPUs, supposing that each thread were bound to a CPU, + # there would exist a perfect hash function mapping threads to + # slots that eliminates collisions. When we reach capacity, we + # search for this mapping by randomly varying the hash codes of + # colliding threads. Because search is random, and collisions + # only become known via CAS failures, convergence can be slow, + # and because threads are typically not bound to CPUS forever, + # may not occur at all. However, despite these limitations, + # observed contention rates are typically low in these cases. + # + # It is possible for a +Cell+ to become unused when threads that + # once hashed to it terminate, as well as in the case where + # doubling the table causes no thread to hash to it under + # expanded mask. We do not try to detect or remove such cells, + # under the assumption that for long-running instances, observed + # contention levels will recur, so the cells will eventually be + # needed again; and for short-lived ones, it does not matter. + class Striped64 + # Padded variant of AtomicLong supporting only raw accesses plus CAS. + # The +value+ field is placed between pads, hoping that the JVM doesn't + # reorder them. + # + # Optimisation note: It would be possible to use a release-only + # form of CAS here, if it were provided. + class Cell < AtomicReference + # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot + attr_reader *(Array.new(12).map {|i| :"padding_#{i}"}) + + alias_method :cas, :compare_and_set + + def cas_computed + cas(current_value = value, yield(current_value)) + end + end + + extend Volatile + attr_volatile :cells, # Table of cells. When non-null, size is a power of 2. + :base, # Base value, used mainly when there is no contention, but also as a fallback during table initialization races. Updated via CAS. + :busy # Spinlock (locked via CAS) used when resizing and/or creating Cells. + + alias_method :busy?, :busy + + def initialize + super() + self.busy = false + self.base = 0 + end + + # Handles cases of updates involving initialization, resizing, + # creating new Cells, and/or contention. See above for + # explanation. This method suffers the usual non-modularity + # problems of optimistic retry code, relying on rechecked sets of + # reads. + # + # Arguments: + # [+x+] + # the value + # [+hash_code+] + # hash code used + # [+x+] + # false if CAS failed before call + def retry_update(x, hash_code, was_uncontended) # :yields: current_value + hash = hash_code + collided = false # True if last slot nonempty + while true + if current_cells = cells + if !(cell = current_cells.volatile_get_by_hash(hash)) + if busy? + collided = false + else # Try to attach new Cell + if try_to_install_new_cell(Cell.new(x), hash) # Optimistically create and try to insert new cell + break + else + redo # Slot is now non-empty + end + end + elsif !was_uncontended # CAS already known to fail + was_uncontended = true # Continue after rehash + elsif cell.cas_computed {|current_value| yield current_value} + break + elsif current_cells.size >= CPU_COUNT || cells != current_cells # At max size or stale + collided = false + elsif collided && expand_table_unless_stale(current_cells) + collided = false + redo # Retry with expanded table + else + collided = true + end + hash = XorShiftRandom.xorshift(hash) + + elsif try_initialize_cells(x, hash) || cas_base_computed {|current_base| yield current_base} + break + end + end + self.hash_code = hash + end + + private + # Static per-thread hash code key. Shared across all instances to + # reduce Thread locals pollution and because adjustments due to + # collisions in one table are likely to be appropriate for + # others. + THREAD_LOCAL_KEY = "#{name}.hash_code".to_sym + + # A thread-local hash code accessor. The code is initially + # random, but may be set to a different value upon collisions. + def hash_code + Thread.current[THREAD_LOCAL_KEY] ||= XorShiftRandom.get + end + + def hash_code=(hash) + Thread.current[THREAD_LOCAL_KEY] = hash + end + + # Sets base and all +cells+ to the given value. + def internal_reset(initial_value) + current_cells = cells + self.base = initial_value + if current_cells + current_cells.each do |cell| + cell.value = initial_value if cell + end + end + end + + def cas_base_computed + cas_base(current_base = base, yield(current_base)) + end + + def free? + !busy? + end + + def try_initialize_cells(x, hash) + if free? && !cells + try_in_busy do + unless cells # Recheck under lock + new_cells = PowerOfTwoTuple.new(2) + new_cells.volatile_set_by_hash(hash, Cell.new(x)) + self.cells = new_cells + end + end + end + end + + def expand_table_unless_stale(current_cells) + try_in_busy do + if current_cells == cells # Recheck under lock + new_cells = current_cells.next_in_size_table + current_cells.each_with_index {|x, i| new_cells.volatile_set(i, x)} + self.cells = new_cells + end + end + end + + def try_to_install_new_cell(new_cell, hash) + try_in_busy do + # Recheck under lock + if (current_cells = cells) && !current_cells.volatile_get(i = current_cells.hash_to_index(hash)) + current_cells.volatile_set(i, new_cell) + end + end + end + + def try_in_busy + if cas_busy(false, true) + begin + yield + ensure + self.busy = false + end + end + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile.rb new file mode 100644 index 0000000..8a8b9fb --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile.rb @@ -0,0 +1,62 @@ +module ThreadSafe + module Util + module Volatile + # Provides +volatile+ (in the JVM's sense) attribute accessors implemented atop of the +AtomicReference+s. + # Usage: + # class Foo + # extend ThreadSafe::Util::Volatile + # attr_volatile :foo, :bar + # + # def initialize(bar) + # super() # must super() into parent initializers before using the volatile attribute accessors + # self.bar = bar + # end + # + # def hello + # my_foo = foo # volatile read + # self.foo = 1 # volatile write + # cas_foo(1, 2) # => true | a strong CAS + # end + # end + def attr_volatile(*attr_names) + return if attr_names.empty? + include(Module.new do + atomic_ref_setup = attr_names.map {|attr_name| "@__#{attr_name} = ThreadSafe::Util::AtomicReference.new"} + initialize_copy_setup = attr_names.zip(atomic_ref_setup).map do |attr_name, ref_setup| + "#{ref_setup}(other.instance_variable_get(:@__#{attr_name}).get)" + end + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def initialize(*) + super + #{atomic_ref_setup.join('; ')} + end + + def initialize_copy(other) + super + #{initialize_copy_setup.join('; ')} + end + RUBY_EVAL + + attr_names.each do |attr_name| + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{attr_name} + @__#{attr_name}.get + end + + def #{attr_name}=(value) + @__#{attr_name}.set(value) + end + + def compare_and_set_#{attr_name}(old_value, new_value) + @__#{attr_name}.compare_and_set(old_value, new_value) + end + RUBY_EVAL + + alias_method :"cas_#{attr_name}", :"compare_and_set_#{attr_name}" + alias_method :"lazy_set_#{attr_name}", :"#{attr_name}=" + end + end) + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile_tuple.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile_tuple.rb new file mode 100644 index 0000000..500beb7 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/volatile_tuple.rb @@ -0,0 +1,46 @@ +module ThreadSafe + module Util + # A fixed size array with volatile volatile getters/setters. + # Usage: + # arr = VolatileTuple.new(16) + # arr.volatile_set(0, :foo) + # arr.volatile_get(0) # => :foo + # arr.cas(0, :foo, :bar) # => true + # arr.volatile_get(0) # => :bar + class VolatileTuple + include Enumerable + + Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : Array + + def initialize(size) + @tuple = tuple = Tuple.new(size) + i = 0 + while i < size + tuple[i] = AtomicReference.new + i += 1 + end + end + + def volatile_get(i) + @tuple[i].get + end + + def volatile_set(i, value) + @tuple[i].set(value) + end + + def compare_and_set(i, old_value, new_value) + @tuple[i].compare_and_set(old_value, new_value) + end + alias_method :cas, :compare_and_set + + def size + @tuple.size + end + + def each + @tuple.each {|ref| yield ref.get} + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/xor_shift_random.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/xor_shift_random.rb new file mode 100644 index 0000000..ad8bf7b --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/util/xor_shift_random.rb @@ -0,0 +1,39 @@ +module ThreadSafe + module Util + # A xorshift random number (positive +Fixnum+s) generator, provides reasonably cheap way to generate thread local random numbers without contending for + # the global +Kernel.rand+. + # Usage: + # x = XorShiftRandom.get # uses Kernel.rand to generate an initial seed + # while true + # if (x = XorShiftRandom.xorshift).odd? # thread-localy generate a next random number + # do_something_at_random + # end + # end + module XorShiftRandom + extend self + MAX_XOR_SHIFTABLE_INT = MAX_INT - 1 + + # Generates an initial non-zero positive +Fixnum+ via +Kernel.rand+. + def get + Kernel.rand(MAX_XOR_SHIFTABLE_INT) + 1 # 0 can't be xorshifted + end + + # xorshift based on: http://www.jstatsoft.org/v08/i14/paper + if 0.size == 4 + # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (3,1,14) to minimise Bignum overflows + def xorshift(x) + x ^= x >> 3 + x ^= (x << 1) & MAX_INT # cut-off Bignum overflow + x ^= x >> 14 + end + else + # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (1,1,54) to minimise Bignum overflows + def xorshift(x) + x ^= x >> 1 + x ^= (x << 1) & MAX_INT # cut-off Bignum overflow + x ^= x >> 54 + end + end + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/lib/thread_safe/version.rb b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/version.rb new file mode 100644 index 0000000..e5e7c92 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/lib/thread_safe/version.rb @@ -0,0 +1,21 @@ +module ThreadSafe + VERSION = "0.3.4" +end + +# NOTE: <= 0.2.0 used Threadsafe::VERSION +# @private +module Threadsafe + + # @private + def self.const_missing(name) + name = name.to_sym + if ThreadSafe.const_defined?(name) + warn "[DEPRECATION] `Threadsafe::#{name}' is deprecated, use `ThreadSafe::#{name}' instead." + ThreadSafe.const_get(name) + else + warn "[DEPRECATION] the `Threadsafe' module is deprecated, please use `ThreadSafe` instead." + super + end + end + +end diff --git a/.gems/gems/thread_safe-0.3.4/test/src/thread_safe/SecurityManager.java b/.gems/gems/thread_safe-0.3.4/test/src/thread_safe/SecurityManager.java new file mode 100644 index 0000000..beb6c02 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/src/thread_safe/SecurityManager.java @@ -0,0 +1,21 @@ +package thread_safe; + +import java.security.Permission; +import java.util.ArrayList; +import java.util.List; + +public class SecurityManager extends java.lang.SecurityManager { + private final List deniedPermissions = + new ArrayList(); + + @Override + public void checkPermission(Permission p) { + if (deniedPermissions.contains(p)) { + throw new SecurityException("Denied!"); + } + } + + public void deny(Permission p) { + deniedPermissions.add(p); + } +} diff --git a/.gems/gems/thread_safe-0.3.4/test/test_array.rb b/.gems/gems/thread_safe-0.3.4/test/test_array.rb new file mode 100644 index 0000000..7a6023a --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/test_array.rb @@ -0,0 +1,18 @@ +require 'thread_safe' +require File.join(File.dirname(__FILE__), "test_helper") + +class TestArray < Minitest::Test + def test_concurrency + ary = ThreadSafe::Array.new + (1..100).map do |i| + Thread.new do + 1000.times do + ary << i + ary.each {|x| x * 2} + ary.shift + ary.last + end + end + end.map(&:join) + end +end diff --git a/.gems/gems/thread_safe-0.3.4/test/test_cache.rb b/.gems/gems/thread_safe-0.3.4/test/test_cache.rb new file mode 100644 index 0000000..1dfb42d --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/test_cache.rb @@ -0,0 +1,901 @@ +require 'thread_safe' +require 'thread' +require File.join(File.dirname(__FILE__), "test_helper") + +Thread.abort_on_exception = true + +class TestCache < Minitest::Test + def setup + @cache = ThreadSafe::Cache.new + end + + def test_concurrency + cache = @cache + (1..100).map do |i| + Thread.new do + 1000.times do |j| + key = i*1000+j + cache[key] = i + cache[key] + cache.delete(key) + end + end + end.map(&:join) + end + + def test_retrieval + assert_size_change 1 do + assert_equal nil, @cache[:a] + assert_equal nil, @cache.get(:a) + @cache[:a] = 1 + assert_equal 1, @cache[:a] + assert_equal 1, @cache.get(:a) + end + end + + def test_put_if_absent + with_or_without_default_proc do + assert_size_change 1 do + assert_equal nil, @cache.put_if_absent(:a, 1) + assert_equal 1, @cache.put_if_absent(:a, 1) + assert_equal 1, @cache.put_if_absent(:a, 2) + assert_equal 1, @cache[:a] + end + end + end + + def test_compute_if_absent + with_or_without_default_proc do + assert_size_change 3 do + assert_equal(1, (@cache.compute_if_absent(:a) {1})) + assert_equal(1, (@cache.compute_if_absent(:a) {2})) + assert_equal 1, @cache[:a] + @cache[:b] = nil + assert_equal(nil, (@cache.compute_if_absent(:b) {1})) + assert_equal(nil, (@cache.compute_if_absent(:c) {})) + assert_equal nil, @cache[:c] + assert_equal true, @cache.key?(:c) + end + end + end + + def test_compute_if_absent_with_return + with_or_without_default_proc { assert_handles_return_lambda(:compute_if_absent, :a) } + end + + def test_compute_if_absent_exception + with_or_without_default_proc { assert_handles_exception(:compute_if_absent, :a) } + end + + def test_compute_if_absent_atomicity + late_compute_threads_count = 10 + late_put_if_absent_threads_count = 10 + getter_threads_count = 5 + compute_started = ThreadSafe::Test::Latch.new(1) + compute_proceed = ThreadSafe::Test::Latch.new(late_compute_threads_count + late_put_if_absent_threads_count + getter_threads_count) + block_until_compute_started = lambda do |name| + if (v = @cache[:a]) != nil + assert_equal nil, v + end + compute_proceed.release + compute_started.await + end + + assert_size_change 1 do + late_compute_threads = Array.new(late_compute_threads_count) do + Thread.new do + block_until_compute_started.call('compute_if_absent') + assert_equal(1, (@cache.compute_if_absent(:a) { flunk })) + end + end + + late_put_if_absent_threads = Array.new(late_put_if_absent_threads_count) do + Thread.new do + block_until_compute_started.call('put_if_absent') + assert_equal(1, @cache.put_if_absent(:a, 2)) + end + end + + getter_threads = Array.new(getter_threads_count) do + Thread.new do + block_until_compute_started.call('getter') + Thread.pass while @cache[:a].nil? + assert_equal 1, @cache[:a] + end + end + + Thread.new do + @cache.compute_if_absent(:a) do + compute_started.release + compute_proceed.await + sleep(0.2) + 1 + end + end.join + (late_compute_threads + late_put_if_absent_threads + getter_threads).each(&:join) + end + end + + def test_compute_if_present + with_or_without_default_proc do + assert_no_size_change do + assert_equal(nil, @cache.compute_if_present(:a) {}) + assert_equal(nil, @cache.compute_if_present(:a) {1}) + assert_equal(nil, @cache.compute_if_present(:a) {flunk}) + assert_equal false, @cache.key?(:a) + end + + @cache[:a] = 1 + assert_no_size_change do + assert_equal(1, @cache.compute_if_present(:a) {1}) + assert_equal(1, @cache[:a]) + assert_equal(2, @cache.compute_if_present(:a) {2}) + assert_equal(2, @cache[:a]) + assert_equal(false, @cache.compute_if_present(:a) {false}) + assert_equal(false, @cache[:a]) + + @cache[:a] = 1 + yielded = false + @cache.compute_if_present(:a) do |old_value| + yielded = true + assert_equal 1, old_value + 2 + end + assert yielded + end + + assert_size_change -1 do + assert_equal(nil, @cache.compute_if_present(:a) {}) + assert_equal(false, @cache.key?(:a)) + assert_equal(nil, @cache.compute_if_present(:a) {1}) + assert_equal(false, @cache.key?(:a)) + end + end + end + + def test_compute_if_present_with_return + with_or_without_default_proc do + @cache[:a] = 1 + assert_handles_return_lambda(:compute_if_present, :a) + end + end + + def test_compute_if_present_exception + with_or_without_default_proc do + @cache[:a] = 1 + assert_handles_exception(:compute_if_present, :a) + end + end + + def test_compute + with_or_without_default_proc do + assert_no_size_change do + assert_compute(:a, nil, nil) {} + end + + assert_size_change 1 do + assert_compute(:a, nil, 1) {1} + assert_compute(:a, 1, 2) {2} + assert_compute(:a, 2, false) {false} + assert_equal false, @cache[:a] + end + + assert_size_change -1 do + assert_compute(:a, false, nil) {} + end + end + end + + def test_compute_with_return + with_or_without_default_proc do + assert_handles_return_lambda(:compute, :a) + @cache[:a] = 1 + assert_handles_return_lambda(:compute, :a) + end + end + + def test_compute_exception + with_or_without_default_proc do + assert_handles_exception(:compute, :a) + @cache[:a] = 1 + assert_handles_exception(:compute, :a) + end + end + + def test_merge_pair + with_or_without_default_proc do + assert_size_change 1 do + assert_equal(nil, @cache.merge_pair(:a, nil) {flunk}) + assert_equal true, @cache.key?(:a) + assert_equal nil, @cache[:a] + end + + assert_no_size_change do + assert_merge_pair(:a, nil, nil, false) {false} + assert_merge_pair(:a, nil, false, 1) {1} + assert_merge_pair(:a, nil, 1, 2) {2} + end + + assert_size_change -1 do + assert_merge_pair(:a, nil, 2, nil) {} + assert_equal false, @cache.key?(:a) + end + end + end + + def test_merge_pair_with_return + with_or_without_default_proc do + @cache[:a] = 1 + assert_handles_return_lambda(:merge_pair, :a, 2) + end + end + + def test_merge_pair_exception + with_or_without_default_proc do + @cache[:a] = 1 + assert_handles_exception(:merge_pair, :a, 2) + end + end + + def test_updates_dont_block_reads + getters_count = 20 + key_klass = ThreadSafe::Test::HashCollisionKey + keys = [key_klass.new(1, 100), key_klass.new(2, 100), key_klass.new(3, 100)] # hash colliding keys + inserted_keys = [] + + keys.each do |key, i| + compute_started = ThreadSafe::Test::Latch.new(1) + compute_finished = ThreadSafe::Test::Latch.new(1) + getters_started = ThreadSafe::Test::Latch.new(getters_count) + getters_finished = ThreadSafe::Test::Latch.new(getters_count) + + computer_thread = Thread.new do + getters_started.await + @cache.compute_if_absent(key) do + compute_started.release + getters_finished.await + 1 + end + compute_finished.release + end + + getter_threads = (1..getters_count).map do + Thread.new do + getters_started.release + inserted_keys.each do |inserted_key| + assert_equal true, @cache.key?(inserted_key) + assert_equal 1, @cache[inserted_key] + end + assert_equal false, @cache.key?(key) + compute_started.await + inserted_keys.each do |inserted_key| + assert_equal true, @cache.key?(inserted_key) + assert_equal 1, @cache[inserted_key] + end + assert_equal false, @cache.key?(key) + assert_equal nil, @cache[key] + getters_finished.release + compute_finished.await + assert_equal true, @cache.key?(key) + assert_equal 1, @cache[key] + end + end + + (getter_threads << computer_thread).map {|t| assert(t.join(2))} # asserting no deadlocks + inserted_keys << key + end + end + + def test_collision_resistance + assert_collision_resistance((0..1000).map {|i| ThreadSafe::Test::HashCollisionKey(i, 1)}) + end + + def test_collision_resistance_with_arrays + special_array_class = Class.new(Array) do + def key # assert_collision_resistance expects to be able to call .key to get the "real" key + first.key + end + end + # Test collision resistance with a keys that say they responds_to <=>, but then raise exceptions + # when actually called (ie: an Array filled with non-comparable keys). + # See https://github.com/headius/thread_safe/issues/19 for more info. + assert_collision_resistance((0..100).map do |i| + special_array_class.new([ThreadSafe::Test::HashCollisionKeyNonComparable.new(i, 1)]) + end) + end + + def test_replace_pair + with_or_without_default_proc do + assert_no_size_change do + assert_equal false, @cache.replace_pair(:a, 1, 2) + assert_equal false, @cache.replace_pair(:a, nil, nil) + assert_equal false, @cache.key?(:a) + end + + @cache[:a] = 1 + assert_no_size_change do + assert_equal true, @cache.replace_pair(:a, 1, 2) + assert_equal false, @cache.replace_pair(:a, 1, 2) + assert_equal 2, @cache[:a] + assert_equal true, @cache.replace_pair(:a, 2, 2) + assert_equal 2, @cache[:a] + assert_equal true, @cache.replace_pair(:a, 2, nil) + assert_equal false, @cache.replace_pair(:a, 2, nil) + assert_equal nil, @cache[:a] + assert_equal true, @cache.key?(:a) + assert_equal true, @cache.replace_pair(:a, nil, nil) + assert_equal true, @cache.key?(:a) + assert_equal true, @cache.replace_pair(:a, nil, 1) + assert_equal 1, @cache[:a] + end + end + end + + def test_replace_if_exists + with_or_without_default_proc do + assert_no_size_change do + assert_equal nil, @cache.replace_if_exists(:a, 1) + assert_equal false, @cache.key?(:a) + end + + @cache[:a] = 1 + assert_no_size_change do + assert_equal 1, @cache.replace_if_exists(:a, 2) + assert_equal 2, @cache[:a] + assert_equal 2, @cache.replace_if_exists(:a, nil) + assert_equal nil, @cache[:a] + assert_equal true, @cache.key?(:a) + assert_equal nil, @cache.replace_if_exists(:a, 1) + assert_equal 1, @cache[:a] + end + end + end + + def test_get_and_set + with_or_without_default_proc do + assert_size_change 1 do + assert_equal nil, @cache.get_and_set(:a, 1) + assert_equal true, @cache.key?(:a) + assert_equal 1, @cache[:a] + assert_equal 1, @cache.get_and_set(:a, 2) + assert_equal 2, @cache.get_and_set(:a, nil) + assert_equal nil, @cache[:a] + assert_equal true, @cache.key?(:a) + assert_equal nil, @cache.get_and_set(:a, 1) + assert_equal 1, @cache[:a] + end + end + end + + def test_key + with_or_without_default_proc do + assert_equal nil, @cache.key(1) + @cache[:a] = 1 + assert_equal :a, @cache.key(1) + assert_equal nil, @cache.key(0) + assert_equal :a, @cache.index(1) if RUBY_VERSION =~ /1\.8/ + end + end + + def test_key? + with_or_without_default_proc do + assert_equal false, @cache.key?(:a) + @cache[:a] = 1 + assert_equal true, @cache.key?(:a) + end + end + + def test_value? + with_or_without_default_proc do + assert_equal false, @cache.value?(1) + @cache[:a] = 1 + assert_equal true, @cache.value?(1) + end + end + + def test_delete + with_or_without_default_proc do |default_proc_set| + assert_no_size_change do + assert_equal nil, @cache.delete(:a) + end + @cache[:a] = 1 + assert_size_change -1 do + assert_equal 1, @cache.delete(:a) + end + assert_no_size_change do + assert_equal nil, @cache[:a] unless default_proc_set + + assert_equal false, @cache.key?(:a) + assert_equal nil, @cache.delete(:a) + end + end + end + + def test_delete_pair + with_or_without_default_proc do + assert_no_size_change do + assert_equal false, @cache.delete_pair(:a, 2) + assert_equal false, @cache.delete_pair(:a, nil) + end + @cache[:a] = 1 + assert_no_size_change do + assert_equal false, @cache.delete_pair(:a, 2) + end + assert_size_change -1 do + assert_equal 1, @cache[:a] + assert_equal true, @cache.delete_pair(:a, 1) + assert_equal false, @cache.delete_pair(:a, 1) + assert_equal false, @cache.key?(:a) + end + end + end + + def test_default_proc + @cache = cache_with_default_proc(1) + assert_no_size_change do + assert_equal false, @cache.key?(:a) + end + assert_size_change 1 do + assert_equal 1, @cache[:a] + assert_equal true, @cache.key?(:a) + end + end + + def test_falsy_default_proc + @cache = cache_with_default_proc(nil) + assert_no_size_change do + assert_equal false, @cache.key?(:a) + end + assert_size_change 1 do + assert_equal nil, @cache[:a] + assert_equal true, @cache.key?(:a) + end + end + + def test_fetch + with_or_without_default_proc do |default_proc_set| + assert_no_size_change do + assert_equal 1, @cache.fetch(:a, 1) + assert_equal(1, (@cache.fetch(:a) {1})) + assert_equal false, @cache.key?(:a) + + assert_equal nil, @cache[:a] unless default_proc_set + end + + @cache[:a] = 1 + assert_no_size_change do + assert_equal(1, (@cache.fetch(:a) {flunk})) + end + + assert_raises(ThreadSafe::Cache::KEY_ERROR) do + @cache.fetch(:b) + end + + assert_no_size_change do + assert_equal 1, (@cache.fetch(:b, :c) {1}) # assert block supersedes default value argument + assert_equal false, @cache.key?(:b) + end + end + end + + def test_falsy_fetch + with_or_without_default_proc do + assert_equal false, @cache.key?(:a) + + assert_no_size_change do + assert_equal(nil, @cache.fetch(:a, nil)) + assert_equal(false, @cache.fetch(:a, false)) + assert_equal(nil, (@cache.fetch(:a) {})) + assert_equal(false, (@cache.fetch(:a) {false})) + end + + @cache[:a] = nil + assert_no_size_change do + assert_equal true, @cache.key?(:a) + assert_equal(nil, (@cache.fetch(:a) {flunk})) + end + end + end + + def test_fetch_with_return + with_or_without_default_proc do + r = lambda do + @cache.fetch(:a) { return 10 } + end.call + + assert_no_size_change do + assert_equal 10, r + assert_equal false, @cache.key?(:a) + end + end + end + + def test_fetch_or_store + with_or_without_default_proc do |default_proc_set| + assert_size_change 1 do + assert_equal 1, @cache.fetch_or_store(:a, 1) + assert_equal 1, @cache[:a] + end + + @cache.delete(:a) + + assert_size_change 1 do + assert_equal 1, (@cache.fetch_or_store(:a) {1}) + assert_equal 1, @cache[:a] + end + + assert_no_size_change do + assert_equal(1, (@cache.fetch_or_store(:a) {flunk})) + end + + assert_raises(ThreadSafe::Cache::KEY_ERROR) do + @cache.fetch_or_store(:b) + end + + assert_size_change 1 do + assert_equal 1, (@cache.fetch_or_store(:b, :c) {1}) # assert block supersedes default value argument + assert_equal 1, @cache[:b] + end + end + end + + def test_falsy_fetch_or_store + with_or_without_default_proc do + assert_equal false, @cache.key?(:a) + + assert_size_change 1 do + assert_equal(nil, @cache.fetch_or_store(:a, nil)) + assert_equal nil, @cache[:a] + assert_equal true, @cache.key?(:a) + end + @cache.delete(:a) + + assert_size_change 1 do + assert_equal(false, @cache.fetch_or_store(:a, false)) + assert_equal false, @cache[:a] + assert_equal true, @cache.key?(:a) + end + @cache.delete(:a) + + assert_size_change 1 do + assert_equal(nil, (@cache.fetch_or_store(:a) {})) + assert_equal nil, @cache[:a] + assert_equal true, @cache.key?(:a) + end + @cache.delete(:a) + + assert_size_change 1 do + assert_equal(false, (@cache.fetch_or_store(:a) {false})) + assert_equal false, @cache[:a] + assert_equal true, @cache.key?(:a) + end + + @cache[:a] = nil + assert_no_size_change do + assert_equal(nil, (@cache.fetch_or_store(:a) {flunk})) + end + end + end + + def test_fetch_or_store_with_return + with_or_without_default_proc do + r = lambda do + @cache.fetch_or_store(:a) { return 10 } + end.call + + assert_no_size_change do + assert_equal 10, r + assert_equal false, @cache.key?(:a) + end + end + end + + def test_clear + @cache[:a] = 1 + assert_size_change -1 do + assert_equal @cache, @cache.clear + assert_equal false, @cache.key?(:a) + assert_equal nil, @cache[:a] + end + end + + def test_each_pair + @cache.each_pair {|k, v| flunk} + assert_equal(@cache, (@cache.each_pair {})) + @cache[:a] = 1 + + h = {} + @cache.each_pair {|k, v| h[k] = v} + assert_equal({:a => 1}, h) + + @cache[:b] = 2 + h = {} + @cache.each_pair {|k, v| h[k] = v} + assert_equal({:a => 1, :b => 2}, h) + end + + def test_each_pair_iterator + @cache[:a] = 1 + @cache[:b] = 2 + i = 0 + r = @cache.each_pair do |k, v| + if i == 0 + i += 1 + next + flunk + elsif i == 1 + break :breaked + end + end + + assert_equal :breaked, r + end + + def test_each_pair_allows_modification + @cache[:a] = 1 + @cache[:b] = 1 + @cache[:c] = 1 + + assert_size_change 1 do + @cache.each_pair do |k, v| + @cache[:z] = 1 + end + end + end + + def test_keys + assert_equal [], @cache.keys + + @cache[1] = 1 + assert_equal [1], @cache.keys + + @cache[2] = 2 + assert_equal [1, 2], @cache.keys.sort + end + + def test_values + assert_equal [], @cache.values + + @cache[1] = 1 + assert_equal [1], @cache.values + + @cache[2] = 2 + assert_equal [1, 2], @cache.values.sort + end + + def test_each_key + assert_equal(@cache, (@cache.each_key {flunk})) + + @cache[1] = 1 + arr = [] + @cache.each_key {|k| arr << k} + assert_equal [1], arr + + @cache[2] = 2 + arr = [] + @cache.each_key {|k| arr << k} + assert_equal [1, 2], arr.sort + end + + def test_each_value + assert_equal(@cache, (@cache.each_value {flunk})) + + @cache[1] = 1 + arr = [] + @cache.each_value {|k| arr << k} + assert_equal [1], arr + + @cache[2] = 2 + arr = [] + @cache.each_value {|k| arr << k} + assert_equal [1, 2], arr.sort + end + + def test_empty + assert_equal true, @cache.empty? + @cache[:a] = 1 + assert_equal false, @cache.empty? + end + + def test_options_validation + assert_valid_options(nil) + assert_valid_options({}) + assert_valid_options(:foo => :bar) + end + + def test_initial_capacity_options_validation + assert_valid_option(:initial_capacity, nil) + assert_valid_option(:initial_capacity, 1) + assert_invalid_option(:initial_capacity, '') + assert_invalid_option(:initial_capacity, 1.0) + assert_invalid_option(:initial_capacity, -1) + end + + def test_load_factor_options_validation + assert_valid_option(:load_factor, nil) + assert_valid_option(:load_factor, 0.01) + assert_valid_option(:load_factor, 0.75) + assert_valid_option(:load_factor, 1) + assert_invalid_option(:load_factor, '') + assert_invalid_option(:load_factor, 0) + assert_invalid_option(:load_factor, 1.1) + assert_invalid_option(:load_factor, 2) + assert_invalid_option(:load_factor, -1) + end + + def test_size + assert_equal 0, @cache.size + @cache[:a] = 1 + assert_equal 1, @cache.size + @cache[:b] = 1 + assert_equal 2, @cache.size + @cache.delete(:a) + assert_equal 1, @cache.size + @cache.delete(:b) + assert_equal 0, @cache.size + end + + def test_get_or_default + with_or_without_default_proc do + assert_equal 1, @cache.get_or_default(:a, 1) + assert_equal nil, @cache.get_or_default(:a, nil) + assert_equal false, @cache.get_or_default(:a, false) + assert_equal false, @cache.key?(:a) + + @cache[:a] = 1 + assert_equal 1, @cache.get_or_default(:a, 2) + end + end + + def test_dup_clone + [:dup, :clone].each do |meth| + cache = cache_with_default_proc(:default_value) + cache[:a] = 1 + dupped = cache.send(meth) + assert_equal 1, dupped[:a] + assert_equal 1, dupped.size + assert_size_change 1, cache do + assert_no_size_change dupped do + cache[:b] = 1 + end + end + assert_equal false, dupped.key?(:b) + assert_no_size_change cache do + assert_size_change -1, dupped do + dupped.delete(:a) + end + end + assert_equal false, dupped.key?(:a) + assert_equal true, cache.key?(:a) + # test default proc + assert_size_change 1, cache do + assert_no_size_change dupped do + assert_equal :default_value, cache[:c] + assert_equal false, dupped.key?(:c) + end + end + assert_no_size_change cache do + assert_size_change 1, dupped do + assert_equal :default_value, dupped[:d] + assert_equal false, cache.key?(:d) + end + end + end + end + + def test_is_unfreezable + assert_raises(NoMethodError) { @cache.freeze } + end + + def test_marshal_dump_load + new_cache = Marshal.load(Marshal.dump(@cache)) + assert_instance_of ThreadSafe::Cache, new_cache + assert_equal 0, new_cache.size + @cache[:a] = 1 + new_cache = Marshal.load(Marshal.dump(@cache)) + assert_equal 1, @cache[:a] + assert_equal 1, new_cache.size + end + + def test_marshal_dump_doesnt_work_with_default_proc + assert_raises(TypeError) do + Marshal.dump(ThreadSafe::Cache.new {}) + end + end + + private + def with_or_without_default_proc + yield false + @cache = ThreadSafe::Cache.new {|h, k| h[k] = :default_value} + yield true + end + + def cache_with_default_proc(default_value = 1) + ThreadSafe::Cache.new {|cache, k| cache[k] = default_value} + end + + def assert_valid_option(option_name, value) + assert_valid_options(option_name => value) + end + + def assert_valid_options(options) + c = ThreadSafe::Cache.new(options) + assert_instance_of ThreadSafe::Cache, c + end + + def assert_invalid_option(option_name, value) + assert_invalid_options(option_name => value) + end + + def assert_invalid_options(options) + assert_raises(ArgumentError) { ThreadSafe::Cache.new(options) } + end + + def assert_size_change(change, cache = @cache) + start = cache.size + yield + assert_equal change, cache.size - start + end + + def assert_no_size_change(cache = @cache, &block) + assert_size_change(0, cache, &block) + end + + def assert_handles_return_lambda(method, key, *args) + before_had_key = @cache.key?(key) + before_had_value = before_had_key ? @cache[key] : nil + + returning_lambda = lambda do + @cache.send(method, key, *args) { return :direct_return } + end + + assert_no_size_change do + assert_equal(:direct_return, returning_lambda.call) + assert_equal before_had_key, @cache.key?(key) + assert_equal before_had_value, @cache[key] if before_had_value + end + end + + class TestException < Exception; end + def assert_handles_exception(method, key, *args) + before_had_key = @cache.key?(key) + before_had_value = before_had_key ? @cache[key] : nil + + assert_no_size_change do + assert_raises(TestException) do + @cache.send(method, key, *args) { raise TestException, '' } + end + assert_equal before_had_key, @cache.key?(key) + assert_equal before_had_value, @cache[key] if before_had_value + end + end + + def assert_compute(key, expected_old_value, expected_result) + result = @cache.compute(:a) do |old_value| + assert_equal expected_old_value, old_value + yield + end + assert_equal expected_result, result + end + + def assert_merge_pair(key, value, expected_old_value, expected_result) + result = @cache.merge_pair(key, value) do |old_value| + assert_equal expected_old_value, old_value + yield + end + assert_equal expected_result, result + end + + def assert_collision_resistance(keys) + keys.each {|k| @cache[k] = k.key} + 10.times do |i| + size = keys.size + while i < size + k = keys[i] + assert(k.key == @cache.delete(k) && !@cache.key?(k) && (@cache[k] = k.key; @cache[k] == k.key)) + i += 10 + end + end + assert(keys.all? {|k| @cache[k] == k.key}) + end +end diff --git a/.gems/gems/thread_safe-0.3.4/test/test_cache_loops.rb b/.gems/gems/thread_safe-0.3.4/test/test_cache_loops.rb new file mode 100644 index 0000000..e3a92ed --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/test_cache_loops.rb @@ -0,0 +1,449 @@ +require 'thread' +require 'thread_safe' +require File.join(File.dirname(__FILE__), "test_helper") + +Thread.abort_on_exception = true + +class TestCacheTorture < Minitest::Test # this is not run unless RUBY_VERSION =~ /1\.8/ || ENV['TRAVIS'] (see the end of the file) + THREAD_COUNT = 40 + KEY_COUNT = (((2**13) - 2) * 0.75).to_i # get close to the doubling cliff + LOW_KEY_COUNT = (((2**8 ) - 2) * 0.75).to_i # get close to the doubling cliff + + INITIAL_VALUE_CACHE_SETUP = lambda do |options, keys| + cache = ThreadSafe::Cache.new + initial_value = options[:initial_value] || 0 + keys.each {|key| cache[key] = initial_value} + cache + end + ZERO_VALUE_CACHE_SETUP = lambda do |options, keys| + INITIAL_VALUE_CACHE_SETUP.call(options.merge(:initial_value => 0), keys) + end + + DEFAULTS = { + :key_count => KEY_COUNT, + :thread_count => THREAD_COUNT, + :loop_count => 1, + :prelude => '', + :cache_setup => lambda {|options, keys| ThreadSafe::Cache.new} + } + + LOW_KEY_COUNT_OPTIONS = {:loop_count => 150, :key_count => LOW_KEY_COUNT} + SINGLE_KEY_COUNT_OPTIONS = {:loop_count => 100_000, :key_count => 1} + + def test_concurrency + code = <<-RUBY_EVAL + cache[key] + cache[key] = key + cache[key] + cache.delete(key) + RUBY_EVAL + do_thread_loop(__method__, code) + end + + def test_put_if_absent + do_thread_loop(__method__, 'acc += 1 unless cache.put_if_absent(key, key)', :key_count => 100_000) do |result, cache, options, keys| + assert_standard_accumulator_test_result(result, cache, options, keys) + end + end + + def test_compute_if_absent + code = 'cache.compute_if_absent(key) { acc += 1; key }' + do_thread_loop(__method__, code) do |result, cache, options, keys| + assert_standard_accumulator_test_result(result, cache, options, keys) + end + end + + def test_compute_put_if_absent + code = <<-RUBY_EVAL + if key.even? + cache.compute_if_absent(key) { acc += 1; key } + else + acc += 1 unless cache.put_if_absent(key, key) + end + RUBY_EVAL + do_thread_loop(__method__, code) do |result, cache, options, keys| + assert_standard_accumulator_test_result(result, cache, options, keys) + end + end + + def test_compute_if_absent_and_present + compute_if_absent_and_present + compute_if_absent_and_present(LOW_KEY_COUNT_OPTIONS) + compute_if_absent_and_present(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_add_remove_to_zero + add_remove_to_zero + add_remove_to_zero(LOW_KEY_COUNT_OPTIONS) + add_remove_to_zero(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_add_remove_to_zero_via_merge_pair + add_remove_to_zero_via_merge_pair + add_remove_to_zero_via_merge_pair(LOW_KEY_COUNT_OPTIONS) + add_remove_to_zero_via_merge_pair(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_add_remove + add_remove + add_remove(LOW_KEY_COUNT_OPTIONS) + add_remove(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_add_remove_via_compute + add_remove_via_compute + add_remove_via_compute(LOW_KEY_COUNT_OPTIONS) + add_remove_via_compute(SINGLE_KEY_COUNT_OPTIONS) + end + + def add_remove_via_compute_if_absent_present + add_remove_via_compute_if_absent_present + add_remove_via_compute_if_absent_present(LOW_KEY_COUNT_OPTIONS) + add_remove_via_compute_if_absent_present(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_add_remove_indiscriminate + add_remove_indiscriminate + add_remove_indiscriminate(LOW_KEY_COUNT_OPTIONS) + add_remove_indiscriminate(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_count_up + count_up + count_up(LOW_KEY_COUNT_OPTIONS) + count_up(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_count_up_via_compute + count_up_via_compute + count_up_via_compute(LOW_KEY_COUNT_OPTIONS) + count_up_via_compute(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_count_up_via_merge_pair + count_up_via_merge_pair + count_up_via_merge_pair(LOW_KEY_COUNT_OPTIONS) + count_up_via_merge_pair(SINGLE_KEY_COUNT_OPTIONS) + end + + def test_count_race + prelude = 'change = (rand(2) == 1) ? 1 : -1' + code = <<-RUBY_EVAL + v = cache[key] + acc += change if cache.replace_pair(key, v, v + change) + RUBY_EVAL + do_thread_loop(__method__, code, :loop_count => 5, :prelude => prelude, :cache_setup => ZERO_VALUE_CACHE_SETUP) do |result, cache, options, keys| + result_sum = sum(result) + assert_equal(sum(keys.map {|key| cache[key]}), result_sum) + assert_equal(sum(cache.values), result_sum) + assert_equal(options[:key_count], cache.size) + end + end + + def test_get_and_set_new + code = 'acc += 1 unless cache.get_and_set(key, key)' + do_thread_loop(__method__, code) do |result, cache, options, keys| + assert_standard_accumulator_test_result(result, cache, options, keys) + end + end + + def test_get_and_set_existing + code = 'acc += 1 if cache.get_and_set(key, key) == -1' + do_thread_loop(__method__, code, :cache_setup => INITIAL_VALUE_CACHE_SETUP, :initial_value => -1) do |result, cache, options, keys| + assert_standard_accumulator_test_result(result, cache, options, keys) + end + end + + private + def compute_if_absent_and_present(opts = {}) + prelude = 'on_present = rand(2) == 1' + code = <<-RUBY_EVAL + if on_present + cache.compute_if_present(key) {|old_value| acc += 1; old_value + 1} + else + cache.compute_if_absent(key) { acc += 1; 1 } + end + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5, :prelude => prelude}.merge(opts)) do |result, cache, options, keys| + stored_sum = 0 + stored_key_count = 0 + keys.each do |k| + if value = cache[k] + stored_sum += value + stored_key_count += 1 + end + end + assert_equal(stored_sum, sum(result)) + assert_equal(stored_key_count, cache.size) + end + end + + def add_remove(opts = {}) + prelude = 'do_add = rand(2) == 1' + code = <<-RUBY_EVAL + if do_add + acc += 1 unless cache.put_if_absent(key, key) + else + acc -= 1 if cache.delete_pair(key, key) + end + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5, :prelude => prelude}.merge(opts)) do |result, cache, options, keys| + assert_all_key_mappings_exist(cache, keys, false) + assert_equal(cache.size, sum(result)) + end + end + + def add_remove_via_compute(opts = {}) + prelude = 'do_add = rand(2) == 1' + code = <<-RUBY_EVAL + cache.compute(key) do |old_value| + if do_add + acc += 1 unless old_value + key + else + acc -= 1 if old_value + nil + end + end + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5, :prelude => prelude}.merge(opts)) do |result, cache, options, keys| + assert_all_key_mappings_exist(cache, keys, false) + assert_equal(cache.size, sum(result)) + end + end + + def add_remove_via_compute_if_absent_present(opts = {}) + prelude = 'do_add = rand(2) == 1' + code = <<-RUBY_EVAL + if do_add + cache.compute_if_absent(key) { acc += 1; key } + else + cache.compute_if_present(key) { acc -= 1; nil } + end + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5, :prelude => prelude}.merge(opts)) do |result, cache, options, keys| + assert_all_key_mappings_exist(cache, keys, false) + assert_equal(cache.size, sum(result)) + end + end + + def add_remove_indiscriminate(opts = {}) + prelude = 'do_add = rand(2) == 1' + code = <<-RUBY_EVAL + if do_add + acc += 1 unless cache.put_if_absent(key, key) + else + acc -= 1 if cache.delete(key) + end + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5, :prelude => prelude}.merge(opts)) do |result, cache, options, keys| + assert_all_key_mappings_exist(cache, keys, false) + assert_equal(cache.size, sum(result)) + end + end + + def count_up(opts = {}) + code = <<-RUBY_EVAL + v = cache[key] + acc += 1 if cache.replace_pair(key, v, v + 1) + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5, :cache_setup => ZERO_VALUE_CACHE_SETUP}.merge(opts)) do |result, cache, options, keys| + assert_count_up(result, cache, options, keys) + end + end + + def count_up_via_compute(opts = {}) + code = <<-RUBY_EVAL + cache.compute(key) do |old_value| + acc += 1 + old_value ? old_value + 1 : 1 + end + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5}.merge(opts)) do |result, cache, options, keys| + assert_count_up(result, cache, options, keys) + result.inject(nil) do |previous_value, next_value| # since compute guarantees atomicity all count ups should be equal + assert_equal previous_value, next_value if previous_value + next_value + end + end + end + + def count_up_via_merge_pair(opts = {}) + code = <<-RUBY_EVAL + cache.merge_pair(key, 1) {|old_value| old_value + 1} + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5}.merge(opts)) do |result, cache, options, keys| + all_match = true + expected_value = options[:loop_count] * options[:thread_count] + keys.each do |key| + if expected_value != (value = cache[key]) + all_match = false + break + end + end + assert all_match + end + end + + def add_remove_to_zero(opts = {}) + code = <<-RUBY_EVAL + acc += 1 unless cache.put_if_absent(key, key) + acc -= 1 if cache.delete_pair(key, key) + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5}.merge(opts)) do |result, cache, options, keys| + assert_all_key_mappings_exist(cache, keys, false) + assert_equal(cache.size, sum(result)) + end + end + + def add_remove_to_zero_via_merge_pair(opts = {}) + code = <<-RUBY_EVAL + acc += (cache.merge_pair(key, key) {}) ? 1 : -1 + RUBY_EVAL + do_thread_loop(__method__, code, {:loop_count => 5}.merge(opts)) do |result, cache, options, keys| + assert_all_key_mappings_exist(cache, keys, false) + assert_equal(cache.size, sum(result)) + end + end + + def do_thread_loop(name, code, options = {}, &block) + options = DEFAULTS.merge(options) + meth = define_loop name, code, options[:prelude] + keys = to_keys_array(options[:key_count]) + run_thread_loop(meth, keys, options, &block) + + if options[:key_count] > 1 + options[:key_count] = (options[:key_count] / 40).to_i + keys = to_hash_collision_keys_array(options[:key_count]) + run_thread_loop(meth, keys, options.merge(:loop_count => (options[:loop_count] * 5)), &block) + end + end + + def run_thread_loop(meth, keys, options) + cache = options[:cache_setup].call(options, keys) + barrier = ThreadSafe::Test::Barrier.new(options[:thread_count]) + result = (1..options[:thread_count]).map do + Thread.new do + setup_sync_and_start_loop(meth, cache, keys, barrier, options[:loop_count]) + end + end.map(&:value) + yield result, cache, options, keys if block_given? + end + + def setup_sync_and_start_loop(meth, cache, keys, barrier, loop_count) + my_keys = keys.shuffle + barrier.await + if my_keys.size == 1 + key = my_keys.first + send("#{meth}_single_key", cache, key, loop_count) + else + send("#{meth}_multiple_keys", cache, my_keys, loop_count) + end + end + + def define_loop(name, body, prelude) + inner_meth_name = :"_#{name}_loop_inner" + outer_meth_name = :"_#{name}_loop_outer" + # looping is splitted into the "loop methods" to trigger the JIT + self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{inner_meth_name}_multiple_keys(cache, keys, i, length, acc) + #{prelude} + target = i + length + while i < target + key = keys[i] + #{body} + i += 1 + end + acc + end unless method_defined?(:#{inner_meth_name}_multiple_keys) + RUBY_EVAL + + self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{inner_meth_name}_single_key(cache, key, i, length, acc) + #{prelude} + target = i + length + while i < target + #{body} + i += 1 + end + acc + end unless method_defined?(:#{inner_meth_name}_single_key) + RUBY_EVAL + + self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{outer_meth_name}_multiple_keys(cache, keys, loop_count) + total_length = keys.size + acc = 0 + inc = 100 + loop_count.times do + i = 0 + pre_loop_inc = total_length % inc + acc = #{inner_meth_name}_multiple_keys(cache, keys, i, pre_loop_inc, acc) + i += pre_loop_inc + while i < total_length + acc = #{inner_meth_name}_multiple_keys(cache, keys, i, inc, acc) + i += inc + end + end + acc + end unless method_defined?(:#{outer_meth_name}_multiple_keys) + RUBY_EVAL + + self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{outer_meth_name}_single_key(cache, key, loop_count) + acc = 0 + i = 0 + inc = 100 + + pre_loop_inc = loop_count % inc + acc = #{inner_meth_name}_single_key(cache, key, i, pre_loop_inc, acc) + i += pre_loop_inc + + while i < loop_count + acc = #{inner_meth_name}_single_key(cache, key, i, inc, acc) + i += inc + end + acc + end unless method_defined?(:#{outer_meth_name}_single_key) + RUBY_EVAL + outer_meth_name + end + + def to_keys_array(key_count) + arr = [] + key_count.times {|i| arr << i} + arr + end + + def to_hash_collision_keys_array(key_count) + to_keys_array(key_count).map {|key| ThreadSafe::Test::HashCollisionKey(key)} + end + + def sum(result) + result.inject(0) {|acc, i| acc + i} + end + + def assert_standard_accumulator_test_result(result, cache, options, keys) + assert_all_key_mappings_exist(cache, keys) + assert_equal(options[:key_count], sum(result)) + assert_equal(options[:key_count], cache.size) + end + + def assert_all_key_mappings_exist(cache, keys, all_must_exist = true) + keys.each do |key| + if (value = cache[key]) || all_must_exist + assert_equal key, value unless key == value # don't do a bazzilion assertions unless necessary + end + end + end + + def assert_count_up(result, cache, options, keys) + keys.each do |key| + unless value = cache[key] + assert value + end + end + assert_equal(sum(cache.values), sum(result)) + assert_equal(options[:key_count], cache.size) + end +end unless RUBY_VERSION =~ /1\.8/ || ENV['TRAVIS'] diff --git a/.gems/gems/thread_safe-0.3.4/test/test_hash.rb b/.gems/gems/thread_safe-0.3.4/test/test_hash.rb new file mode 100644 index 0000000..12f4975 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/test_hash.rb @@ -0,0 +1,17 @@ +require 'thread_safe' +require File.join(File.dirname(__FILE__), "test_helper") + +class TestHash < Minitest::Test + def test_concurrency + hsh = ThreadSafe::Hash.new + (1..100).map do |i| + Thread.new do + 1000.times do |j| + hsh[i*1000+j] = i + hsh[i*1000+j] + hsh.delete(i*1000+j) + end + end + end.map(&:join) + end +end diff --git a/.gems/gems/thread_safe-0.3.4/test/test_helper.rb b/.gems/gems/thread_safe-0.3.4/test/test_helper.rb new file mode 100644 index 0000000..9e49ad4 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/test_helper.rb @@ -0,0 +1,113 @@ +require 'thread' +require 'rubygems' +gem 'minitest', '>= 4' +require 'minitest/autorun' + +if Minitest.const_defined?('Test') + # We're on Minitest 5+. Nothing to do here. +else + # Minitest 4 doesn't have Minitest::Test yet. + Minitest::Test = MiniTest::Unit::TestCase +end + +if defined?(JRUBY_VERSION) && ENV['TEST_NO_UNSAFE'] + # to be used like this: rake test TEST_NO_UNSAFE=true + load 'test/package.jar' + java_import 'thread_safe.SecurityManager' + manager = SecurityManager.new + + # Prevent accessing internal classes + manager.deny java.lang.RuntimePermission.new("accessClassInPackage.sun.misc") + java.lang.System.setSecurityManager manager + + class TestNoUnsafe < Minitest::Test + def test_security_manager_is_used + begin + java_import 'sun.misc.Unsafe' + flunk + rescue SecurityError + end + end + + def test_no_unsafe_version_of_chmv8_is_used + require 'thread_safe/jruby_cache_backend' # make sure the jar has been loaded + assert !Java::OrgJrubyExtThread_safe::JRubyCacheBackendLibrary::JRubyCacheBackend::CAN_USE_UNSAFE_CHM + end + end +end + +module ThreadSafe + module Test + class Latch + def initialize(count = 1) + @count = count + @mutex = Mutex.new + @cond = ConditionVariable.new + end + + def release + @mutex.synchronize do + @count -= 1 if @count > 0 + @cond.broadcast if @count.zero? + end + end + + def await + @mutex.synchronize do + @cond.wait @mutex if @count > 0 + end + end + end + + class Barrier < Latch + def await + @mutex.synchronize do + if @count.zero? # fall through + elsif @count > 0 + @count -= 1 + @count.zero? ? @cond.broadcast : @cond.wait(@mutex) + end + end + end + end + + class HashCollisionKey + attr_reader :hash, :key + def initialize(key, hash = key.hash % 3) + @key = key + @hash = hash + end + + def eql?(other) + other.kind_of?(self.class) && @key.eql?(other.key) + end + + def even? + @key.even? + end + + def <=>(other) + @key <=> other.key + end + end + + # having 4 separate HCK classes helps for a more thorough CHMV8 testing + class HashCollisionKey2 < HashCollisionKey; end + class HashCollisionKeyNoCompare < HashCollisionKey + def <=>(other) + 0 + end + end + class HashCollisionKey4 < HashCollisionKeyNoCompare; end + + HASH_COLLISION_CLASSES = [HashCollisionKey, HashCollisionKey2, HashCollisionKeyNoCompare, HashCollisionKey4] + + def self.HashCollisionKey(key, hash = key.hash % 3) + HASH_COLLISION_CLASSES[rand(4)].new(key, hash) + end + + class HashCollisionKeyNonComparable < HashCollisionKey + undef <=> + end + end +end diff --git a/.gems/gems/thread_safe-0.3.4/test/test_synchronized_delegator.rb b/.gems/gems/thread_safe-0.3.4/test/test_synchronized_delegator.rb new file mode 100644 index 0000000..40c9438 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/test/test_synchronized_delegator.rb @@ -0,0 +1,84 @@ +require 'thread_safe/synchronized_delegator.rb' +require File.join(File.dirname(__FILE__), "test_helper") + +class TestSynchronizedDelegator < Minitest::Test + + def test_wraps_array + sync_array = SynchronizedDelegator.new(array = []) + + array << 1 + assert_equal 1, sync_array[0] + + sync_array << 2 + assert_equal 2, array[1] + end + + def test_synchronizes_access + t1_continue, t2_continue = false, false + + hash = Hash.new do |hash, key| + t2_continue = true + unless hash.find { |e| e[1] == key.to_s } # just to do something + hash[key] = key.to_s + Thread.pass until t1_continue + end + end + sync_hash = SynchronizedDelegator.new(hash) + sync_hash[1] = 'egy' + + t1 = Thread.new do + sync_hash[2] = 'dva' + sync_hash[3] # triggers t2_continue + end + + t2 = Thread.new do + Thread.pass until t2_continue + sync_hash[4] = '42' + end + + sleep(0.05) # sleep some to allow threads to boot + + until t2.status == 'sleep' do + Thread.pass + end + + assert_equal 3, hash.keys.size + + t1_continue = true + t1.join; t2.join + + assert_equal 4, sync_hash.size + end + + def test_synchronizes_access_with_block + t1_continue, t2_continue = false, false + + sync_array = SynchronizedDelegator.new(array = []) + + t1 = Thread.new do + sync_array << 1 + sync_array.each do + t2_continue = true + Thread.pass until t1_continue + end + end + + t2 = Thread.new do + # sleep(0.01) + Thread.pass until t2_continue + sync_array << 2 + end + + until t2.status == 'sleep' || t2.status == false do + Thread.pass + end + + assert_equal 1, array.size + + t1_continue = true + t1.join; t2.join + + assert_equal [1, 2], array + end + +end diff --git a/.gems/gems/thread_safe-0.3.4/thread_safe.gemspec b/.gems/gems/thread_safe-0.3.4/thread_safe.gemspec new file mode 100644 index 0000000..be217a0 --- /dev/null +++ b/.gems/gems/thread_safe-0.3.4/thread_safe.gemspec @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +$:.push File.expand_path('../lib', __FILE__) unless $:.include?('lib') +require 'thread_safe/version' + +Gem::Specification.new do |gem| + gem.authors = ["Charles Oliver Nutter", "thedarkone"] + gem.email = ["headius@headius.com", "thedarkone2@gmail.com"] + gem.description = %q{Thread-safe collections and utilities for Ruby} + gem.summary = %q{A collection of data structures and utilities to make thread-safe programming in Ruby easier} + gem.homepage = "https://github.com/headius/thread_safe" + + gem.files = `git ls-files`.split($\) + gem.files += ['lib/thread_safe/jruby_cache_backend.jar'] if defined?(JRUBY_VERSION) + gem.files -= ['.gitignore'] # see https://github.com/headius/thread_safe/issues/40#issuecomment-42315441 + gem.platform = 'java' if defined?(JRUBY_VERSION) + gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) + gem.name = "thread_safe" + gem.require_paths = ["lib"] + gem.version = ThreadSafe::VERSION + gem.license = "Apache-2.0" + + gem.add_development_dependency 'atomic', ['>= 1.1.7', '< 2'] + gem.add_development_dependency 'rake' + gem.add_development_dependency 'minitest', '>= 4' +end diff --git a/.gems/specifications/addressable-2.3.6.gemspec b/.gems/specifications/addressable-2.3.6.gemspec new file mode 100644 index 0000000..55c1cbc --- /dev/null +++ b/.gems/specifications/addressable-2.3.6.gemspec @@ -0,0 +1,39 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "addressable" + s.version = "2.3.6" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Bob Aman"] + s.date = "2014-03-24" + s.description = "Addressable is a replacement for the URI implementation that is part of\nRuby's standard library. It more closely conforms to the relevant RFCs and\nadds support for IRIs and URI templates.\n" + s.email = "bob@sporkmonger.com" + s.extra_rdoc_files = ["README.md"] + s.files = ["README.md"] + s.homepage = "http://addressable.rubyforge.org/" + s.licenses = ["Apache License 2.0"] + s.rdoc_options = ["--main", "README.md"] + s.require_paths = ["lib"] + s.rubyforge_project = "addressable" + s.rubygems_version = "2.0.14" + s.summary = "URI Implementation" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, [">= 0.7.3"]) + s.add_development_dependency(%q, [">= 2.9.0"]) + s.add_development_dependency(%q, [">= 0.3.2"]) + else + s.add_dependency(%q, [">= 0.7.3"]) + s.add_dependency(%q, [">= 2.9.0"]) + s.add_dependency(%q, [">= 0.3.2"]) + end + else + s.add_dependency(%q, [">= 0.7.3"]) + s.add_dependency(%q, [">= 2.9.0"]) + s.add_dependency(%q, [">= 0.3.2"]) + end +end diff --git a/.gems/specifications/buftok-0.2.0.gemspec b/.gems/specifications/buftok-0.2.0.gemspec new file mode 100644 index 0000000..ba01c3b --- /dev/null +++ b/.gems/specifications/buftok-0.2.0.gemspec @@ -0,0 +1,29 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "buftok" + s.version = "0.2.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 1.3.5") if s.respond_to? :required_rubygems_version= + s.authors = ["Tony Arcieri", "Martin Emde", "Erik Michaels-Ober"] + s.date = "2013-11-22" + s.description = "BufferedTokenizer extracts token delimited entities from a sequence of arbitrary inputs" + s.email = "sferik@gmail.com" + s.homepage = "https://github.com/sferik/buftok" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "BufferedTokenizer extracts token delimited entities from a sequence of arbitrary inputs" + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["~> 1.0"]) + else + s.add_dependency(%q, ["~> 1.0"]) + end + else + s.add_dependency(%q, ["~> 1.0"]) + end +end diff --git a/.gems/specifications/equalizer-0.0.9.gemspec b/.gems/specifications/equalizer-0.0.9.gemspec new file mode 100644 index 0000000..2a30b2c --- /dev/null +++ b/.gems/specifications/equalizer-0.0.9.gemspec @@ -0,0 +1,31 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "equalizer" + s.version = "0.0.9" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Dan Kubb", "Markus Schirp"] + s.date = "2013-12-23" + s.description = "Module to define equality, equivalence and inspection methods" + s.email = ["dan.kubb@gmail.com", "mbj@schirp-dso.com"] + s.extra_rdoc_files = ["LICENSE", "README.md", "CONTRIBUTING.md"] + s.files = ["LICENSE", "README.md", "CONTRIBUTING.md"] + s.homepage = "https://github.com/dkubb/equalizer" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "Module to define equality, equivalence and inspection methods" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, [">= 1.3.5", "~> 1.3"]) + else + s.add_dependency(%q, [">= 1.3.5", "~> 1.3"]) + end + else + s.add_dependency(%q, [">= 1.3.5", "~> 1.3"]) + end +end diff --git a/.gems/specifications/faraday-0.9.0.gemspec b/.gems/specifications/faraday-0.9.0.gemspec new file mode 100644 index 0000000..35b8c20 --- /dev/null +++ b/.gems/specifications/faraday-0.9.0.gemspec @@ -0,0 +1,31 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "faraday" + s.version = "0.9.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 1.3.5") if s.respond_to? :required_rubygems_version= + s.authors = ["Rick Olson"] + s.date = "2014-01-16" + s.email = "technoweenie@gmail.com" + s.homepage = "https://github.com/lostisland/faraday" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "HTTP/REST API client library." + + if s.respond_to? :specification_version then + s.specification_version = 2 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q, ["< 3", ">= 1.2"]) + s.add_development_dependency(%q, ["~> 1.0"]) + else + s.add_dependency(%q, ["< 3", ">= 1.2"]) + s.add_dependency(%q, ["~> 1.0"]) + end + else + s.add_dependency(%q, ["< 3", ">= 1.2"]) + s.add_dependency(%q, ["~> 1.0"]) + end +end diff --git a/.gems/specifications/http-0.6.2.gemspec b/.gems/specifications/http-0.6.2.gemspec new file mode 100644 index 0000000..6065dfb --- /dev/null +++ b/.gems/specifications/http-0.6.2.gemspec @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "http" + s.version = "0.6.2" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Tony", "Arcieri"] + s.date = "2014-08-06" + s.description = "An easy-to-use client library for making requests from Ruby. It uses a simple method chaining system for building requests, similar to Python's Requests." + s.email = ["tony.arcieri@gmail.com"] + s.homepage = "https://github.com/tarcieri/http" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "HTTP should be easy" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q, ["~> 0.6.0"]) + s.add_development_dependency(%q, ["~> 1.0"]) + else + s.add_dependency(%q, ["~> 0.6.0"]) + s.add_dependency(%q, ["~> 1.0"]) + end + else + s.add_dependency(%q, ["~> 0.6.0"]) + s.add_dependency(%q, ["~> 1.0"]) + end +end diff --git a/.gems/specifications/http_parser.rb-0.6.0.gemspec b/.gems/specifications/http_parser.rb-0.6.0.gemspec new file mode 100644 index 0000000..0214801 --- /dev/null +++ b/.gems/specifications/http_parser.rb-0.6.0.gemspec @@ -0,0 +1,46 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "http_parser.rb" + s.version = "0.6.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Marc-Andre Cournoyer", "Aman Gupta"] + s.date = "2013-12-11" + s.description = "Ruby bindings to http://github.com/ry/http-parser and http://github.com/a2800276/http-parser.java" + s.email = ["macournoyer@gmail.com", "aman@tmm1.net"] + s.extensions = ["ext/ruby_http_parser/extconf.rb"] + s.files = ["ext/ruby_http_parser/extconf.rb"] + s.homepage = "http://github.com/tmm1/http_parser.rb" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "Simple callback-based HTTP request/response parser" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, [">= 0.7.9"]) + s.add_development_dependency(%q, [">= 2.0.1"]) + s.add_development_dependency(%q, [">= 1.4.6"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0.8.1"]) + else + s.add_dependency(%q, [">= 0.7.9"]) + s.add_dependency(%q, [">= 2.0.1"]) + s.add_dependency(%q, [">= 1.4.6"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0.8.1"]) + end + else + s.add_dependency(%q, [">= 0.7.9"]) + s.add_dependency(%q, [">= 2.0.1"]) + s.add_dependency(%q, [">= 1.4.6"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0.8.1"]) + end +end diff --git a/.gems/specifications/memoizable-0.4.2.gemspec b/.gems/specifications/memoizable-0.4.2.gemspec new file mode 100644 index 0000000..750ac88 --- /dev/null +++ b/.gems/specifications/memoizable-0.4.2.gemspec @@ -0,0 +1,34 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "memoizable" + s.version = "0.4.2" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Dan Kubb", "Erik Michaels-Ober"] + s.date = "2014-03-27" + s.description = "Memoize method return values" + s.email = ["dan.kubb@gmail.com", "sferik@gmail.com"] + s.extra_rdoc_files = ["CONTRIBUTING.md", "LICENSE.md", "README.md"] + s.files = ["CONTRIBUTING.md", "LICENSE.md", "README.md"] + s.homepage = "https://github.com/dkubb/memoizable" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "Memoize method return values" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q, [">= 0.3.1", "~> 0.3"]) + s.add_development_dependency(%q, [">= 1.5.3", "~> 1.5"]) + else + s.add_dependency(%q, [">= 0.3.1", "~> 0.3"]) + s.add_dependency(%q, [">= 1.5.3", "~> 1.5"]) + end + else + s.add_dependency(%q, [">= 0.3.1", "~> 0.3"]) + s.add_dependency(%q, [">= 1.5.3", "~> 1.5"]) + end +end diff --git a/.gems/specifications/multipart-post-2.0.0.gemspec b/.gems/specifications/multipart-post-2.0.0.gemspec new file mode 100644 index 0000000..21bff89 --- /dev/null +++ b/.gems/specifications/multipart-post-2.0.0.gemspec @@ -0,0 +1,19 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "multipart-post" + s.version = "2.0.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Nick Sieger"] + s.date = "2013-12-21" + s.description = "Use with Net::HTTP to do multipart form posts. IO values that have #content_type, #original_filename, and #local_path will be posted as a binary file." + s.email = ["nick@nicksieger.com"] + s.homepage = "https://github.com/nicksieger/multipart-post" + s.licenses = ["MIT"] + s.rdoc_options = ["--main", "README.md", "-SHN", "-f", "darkfish"] + s.require_paths = ["lib"] + s.rubyforge_project = "caldersphere" + s.rubygems_version = "2.0.14" + s.summary = "A multipart form post accessory for Net::HTTP." +end diff --git a/.gems/specifications/naught-1.0.0.gemspec b/.gems/specifications/naught-1.0.0.gemspec new file mode 100644 index 0000000..3ceec69 --- /dev/null +++ b/.gems/specifications/naught-1.0.0.gemspec @@ -0,0 +1,29 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "naught" + s.version = "1.0.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Avdi Grimm"] + s.date = "2014-01-26" + s.description = "Naught is a toolkit for building Null Objects" + s.email = ["avdi@avdi.org"] + s.homepage = "https://github.com/avdi/naught" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "Naught is a toolkit for building Null Objects" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["~> 1.3"]) + else + s.add_dependency(%q, ["~> 1.3"]) + end + else + s.add_dependency(%q, ["~> 1.3"]) + end +end diff --git a/.gems/specifications/simple_oauth-0.2.0.gemspec b/.gems/specifications/simple_oauth-0.2.0.gemspec new file mode 100644 index 0000000..ce1a411 --- /dev/null +++ b/.gems/specifications/simple_oauth-0.2.0.gemspec @@ -0,0 +1,35 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "simple_oauth" + s.version = "0.2.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Steve Richert", "Erik Michaels-Ober"] + s.date = "2012-12-02" + s.description = "Simply builds and verifies OAuth headers" + s.email = ["steve.richert@gmail.com", "sferik@gmail.com"] + s.homepage = "https://github.com/laserlemon/simple_oauth" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "Simply builds and verifies OAuth headers" + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 2"]) + s.add_development_dependency(%q, [">= 0"]) + else + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2"]) + s.add_dependency(%q, [">= 0"]) + end + else + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2"]) + s.add_dependency(%q, [">= 0"]) + end +end diff --git a/.gems/specifications/thread_safe-0.3.4.gemspec b/.gems/specifications/thread_safe-0.3.4.gemspec new file mode 100644 index 0000000..9883cc4 --- /dev/null +++ b/.gems/specifications/thread_safe-0.3.4.gemspec @@ -0,0 +1,35 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "thread_safe" + s.version = "0.3.4" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Charles Oliver Nutter", "thedarkone"] + s.date = "2014-05-27" + s.description = "Thread-safe collections and utilities for Ruby" + s.email = ["headius@headius.com", "thedarkone2@gmail.com"] + s.homepage = "https://github.com/headius/thread_safe" + s.licenses = ["Apache-2.0"] + s.require_paths = ["lib"] + s.rubygems_version = "2.0.14" + s.summary = "A collection of data structures and utilities to make thread-safe programming in Ruby easier" + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["< 2", ">= 1.1.7"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 4"]) + else + s.add_dependency(%q, ["< 2", ">= 1.1.7"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 4"]) + end + else + s.add_dependency(%q, ["< 2", ">= 1.1.7"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 4"]) + end +end diff --git a/.gems/specifications/twitter-5.11.0.gemspec b/.gems/specifications/twitter-5.11.0.gemspec index dcad08f..fbf9260 100644 --- a/.gems/specifications/twitter-5.11.0.gemspec +++ b/.gems/specifications/twitter-5.11.0.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |s| s.homepage = "http://sferik.github.com/twitter/" s.licenses = ["MIT"] s.require_paths = ["lib"] - s.rubygems_version = "1.8.23" + s.rubygems_version = "2.0.14" s.summary = "A Ruby interface to the Twitter API." if s.respond_to? :specification_version then

    +
    Homepage
    addressable.rubyforge.org
    +
    Author
    Bob Aman
    +
    Copyright
    Copyright © 2006-2013 Bob Aman
    +
    License
    Apache 2.0
    +

    J@rLEm;nbVnOn*&^3V(ghbY8wiY| z_K%F3gm!R~-?y5hHL zn5yl+inFXp=Mn=V_XlJ7LA#gs6z)mmGcH4bmf>lXWh|~F*sLf)2}T$jMlWJ@Av3i| zvRs*rgeTKs>ok&9pb9Y^eVI(Y+=Px0Qr$95phQ7t@LXwJS*y><+>b^Ms*E-u3XHY1 zg-SSm966~9>r)6UNjoxtmLx)OLmLaRYOZFKQo`RjEVw@;*8-=yDuE(TOj30$5mz8F z{ZC`5(#j1>ibZ1)PjWHLC?lG&1L#&1(kPU%Ltu`<0Fg{gOk7Kd4I-%^m4pNuwNT%PG+?y^ zYNg@nPRBfy3$E%UP&5biiSsyBZ6faWSJFWTLZ>WrDvKT1PBa9yO5}c?@w9Be)W#rn z0!nSlX*EjHu{^=61jEiO4-kPT){@dgkkkTfTLc|$TZIL7bGt!8EbcXSv$Dd6-gT0h z=hT-XcqKN@EJ7V)vf;P{4yh!)Vwmstc3!{z{`ua))A!%we{XmHKYQQW);5wg_odbAgG@2Wx~+X- z#)VBn)QUU>-mIfCX2 zVoBOjq5c|m%p$w$oWadV)6Ek$6{~WBQ$r&lZU7YFfd8bN9)e=i#UZIN<)FtMZ>}?% z(e<(sbOHZo6S2C8#<>=SWVv3rzDh7%O(3^!B2<_o!BxaxE`um-EU`(cZ44Y{GA1l~ zQbv+^AnNjS4vH}3N{hu>6D~Q3W0DyN6+cdWR&h5_NyR+gaAr!WJLS}D zGNh#;oF>-LqrUNk_kmG7#>m7b%0+^p0`r@kXf125t*s+16M2?e>$J?$ibjD!Di?vI z2|wzz5UX=h1QeOsah{0PP}SqH#_18#a&2l>cb>x;$$bv;0bD#n;X!HQ*f*OptDzlA zBZN5ngcYRLpnW0LnNd+U4&Lx5v1JWw$;FoH85#hO0o5=px+6ZQ-x3*z!lr>IJWS&14mg7=YEqNI%~H9YZvq!rOAvADTRHZMJS zh$qbG*ci-QQdicx-=EFS%<_lS~cekVpwUJ4z38U4T?%x zEv}mqk+e^;P)Zv*HKY$*8aDEG@BFPT4tq3K1v3q1k_56JP+u&KDTWY3$$=I0s)!An z^bTWWpNDWXQ<%q(Bxoc#+vGk;-w!l8DYKyx$m#G@N*pad#1&VH88D|4E}~ zh-tNX1zI?_Te_Qz3k7+@3*U^Y>xFQ|(wdv=&)eK8acwt$7vY9#*mhyM9?Y`GMevDf z!T*N#zyxUV6W!8`rU-Z!aUIn9V2ZVb>k_e*u_6`$!DGcaEl?OuHEa{gv`O_H9V~;< z+?NeApP&7TQmh6H4gKCIL8ZbD%MV&5lW@YMep6l(=r?)Zp>vi?&eafX(O}K8EwQ3P zD3;MrNZf^qPTE>YT}^H|KxkPjDUE`tH4=VwB$p8DL=LBBedq6ePw4;MljLxb;C%PnDqu+o8uXVT9Fg0v*4SwF%V7FQwxPFr6 zc1!vIYO|(m#TWhZO(FZ;>dx;MPSz&e;!~O6k}QhQRCM@{y{B)U9{gPbTBAb}>1i#E zuBYiyEL1EM&$jpa7u33>s|tc#w~y==k-^rw1V}Lb&(l&HnS3 zG=e~pmv6%-FWw%!2_6C~_o(pnHlRQ+*lL)VDD-nZI4CB4)KYMPmuQnBjPG^2?ptoo zPxbd>Jbt_Qt!{$BXK3m}g2za2@R8=EK`DXP6Hbx}<;^3wgSRHtlb zCS@~LoCg42{3g5(5`8#@=O7RtaSu~;2d152xrVKL%B_gl)%a5~ZL1zwf{VxGVXIhK zvQ4thVFOL`S_>dg@v7>fSW???574Z(<-@|hUaAYqGMnW+Rv-=IsdCbXn?NrniV3Xv zgAGC7?Ihli%nA|w_^!4l7R-vtRK@Y&+u9t4ImZk5ye2zjg>ym|4{ ziyo{Bqt97vy@nY-GI)!e(0|uMGK@xS`XV=Fu4)rnPnd@MQxs{}32luYMB;38oqNR7 z>^OWGMeNe4<={_)1%1>!IX7j2mdnQTBye>a#VRZosODdo&=069o|8x9s*FI_-&~=s!E?%l4=U zh$Dy;pK!!A%7R3e#lC=mFE;2xUX`xo1S>EAHkyu68L}Hikt*aPzxd(s?r@zvYFd&h z-ZLF^tS}!tU!9__QysZ{HD@8_+_*Qe{xSL1zJ?^0hX6H^9i$W%1=G7|Bp9ulwF0Jvt za6<&21Lqnrg2laSVW$JYY1KJF#eprE7&X}QNN`i2s65Ar?&5cA|Fw%>qk@vTvtE@J z2u%2ZQ2>J&)4~ci!AdGH7hPDS0+w00`MF5s!4#@jD<&w;0oLf+swYS1$7zO6DMRME zOz8!MpI(oiG+YUU-|>@%D^2iAbAe5%fZu9rK@ARG{3Cp|50V@AfxT>S7K5Mmf8Klh z>`nM&@8#Z;r*HlX-jELtz`FNO{gl7q`vYG*J$NIh$of$-!4hjhf}XUk;^imQ@Y0Ny zOV=dfBsq&&mki7T&#A4YH@gY$`PgY5T>RMT2|b!4C0pyaTl*~jmT`new&tyNT=bs)Me0wW3gdN zxiD17=*EDJyJIw2C8u#)r^|G@RQ^Y-2r=Q7fqtkAG4wJV4JkhJ_KC{EHd!}V;IRY7 z2svN}(bi5&Bb{8xV6x@y5pfAlXEYmOkQ-@E+_Lw2I1=3~vy`__Mmd6j#TSx)7&_@n z)bV`TGd-espB#~ve6@ww$I^@?4-?tLC?k|r&O!zK;jxqb0;v_hzAFR=zDJF% zdzc%>-D5(JT&)^lm!}+316c5;+jR>IbX(Nmk^N`S37m9qyIenJNvrYK<%yDj4mnrxbLF}s-*UL!1Mp(Ce7#(2wcI;msj11^>Y z+Dn_KR0BBa_2EuH@*U=O?kcl5QNbE!aeeNAnRfu)T__ww?opj4*AK0rupV=fD5(Z*ujba?bjo zzR%8_E7aAJewBOkD_>apFzZXpk5lz8tA@*}>p_;erP$}dM8}e&sQr~Z-v0@5;~aty}i#HMhWY+w#s?<+y6tem@v2Ep@3Cf}Qn_5L=oz#P9ZrF)%-o z4e7WAT5rck+IaOqcW55+8b{nYz3SZfMM~AQE7=W z8-{C)blWifC0ws5IfJ%GjP%%qsQQ$uK}`=Cc#%Q>utM@Fz}X z3)rkJV6yNnT!R=w8f!;>rRo#DRGza(+214(ghlcg7>eqr(p_Aq3M60iPVjmfPjV_b zfGSv>7lD#?kz4RcphibCpd(q4_j=BHDb@=t4cW1Fmo~*d;z>0&)V;^;JKEXpt6iSu zG+?NAC0RK>-c<>Yg4(P4DAfxT${tQk*~_?Rb!(|iIZtf zT&2p0$W6#3y()KzPS2%c5r{-Y;=@rgosL9k5T!RwxMVj)YRh1;PJoW}B819H9Y%Ff zbPD*Mcpr2-!P7$(6=hg2+QN}jHr%F$7=1x>5W~nQ%Nx4&$V3{l?H$z?jY)Akkl8jg zeZt`O4hNE>{YB=%xKCcg_(wa)(dCn(8ivClHL^iSwU~t#v_mt~(Yy^4>6GtSBDAFFKJ1eMk=mH!>WA035 zPm^JF>?(yr=!njtw9F~TX6&aWgOw;!i7R%(s}0-`oR@%10DguBQ#v&rYt3G#C-E>6 zp<}~%N`u0T5xX!zik&YB(I~IUNpf^d_3EfYX^zFvJe_upEI$~#A+ol046BZhdzOhB zLQ~8@!qE=CBUhcTVafPnlBX>nekqBt%$RXY8#8WcSNBy)mxq{9kivjE&(P}-kx|7c zlKd2NvfaO$99kErYD=ar)|vHN7Zp*15{tw+h`$z*H_ zy3m3UXz$|UVK9ECbiNchSHV>gOcNBNddk=}Uwt&=kXNZbY8!}@=bv1aVHy(UL!*2s zE=fB?&aapBx*aZUAod!EnW$E9wSL$UQZ8-8)kU{O$m_;K5s|5qOj|)vdOkc>(MQrD z!~*8IN_fLVu>dVr2`WyaxW7KL!?m#k|7PZ3--T6f4A#`h9|Ng8CtR_s=o?+36<58~ zh_n26)R>zaDldBrm9M~zI4ir9y8OCL&oWABSd2KnA}iuKk@Xphd5na0@l<(01e|_l z*Y!*is<%o_1j*te0;)9VTk-=od~!VtG0yXSI_A%53EEBYlw;E}82$xOXAT$pMKP$AB(Kj(Knd|xHkSD{^7_Jqvi1nZp^bKz92TRt$vB6>z0a~_KqK7T%DyqvU6T|y-MpIb+g;D<6Z=yfFwmK zP}`5-i{C!21wgTOsbHU*Bh%rcJ8RXLbB2tCtbGnF7%`T{dVm4fAOaLkKAfDUYPE=`a4Y6+8-zmkfKa%2B;IrG;4C!WyrV z#$RW2IusS)fx?&uo%)6<*C)9k$zjx>H)zi=x4t5rbHhK(NC~^>4Hk~U9QM-DUTdly z=Y2}o;n;Rq_}(`EeDDCxUQBHGL127ov@F<(6@KM1gPBe&Nj+upAf;4iXqvFH$aZ{K zYRa^naLg8zE-q}Y|_gEb!Eu-B}$wiDBqrm2Sn?JPew1JOG#tFoXP%9VkB}7&ot8KCoO)8dt}13l~MoR{L8kxYC&0g9jKV zzhOP2nEMJ`oTEQjWEu@CKH6L|y_Rijom*9w1ZR7tPH(PTfw^z&UA0Qr6`G>0AhfdM z=tN%ou52|%y*SqA>1nKt(!f|Gv52{oDg9NF>}hJ`7oL~ThaHg_K`g{Tp3B1dg0~B5 zl`Q|6sUUivP*=p8XWkpDoPTg-^|RggC2F5nKdbI&jLVgV%0WPhJF~!u+9k?L>b-HTVE!?Y8sm_=ah(`8+EMLIR z`a-^oGHzKe9Y$b=O$Og?Y;ZP~`heOr0Jq2`9v;HsqN?|-$%KT;uqRSr7*~s(JXRD1 zDn}r=coQcw$M242O{!JnlVH7YE=u|+81eKf67~aIFZanlUIlZ6Zv@ASn8<*2 z3eYx2)PXYgIOo(^GxSt((9iO6ETF^r{p8>&Zl%B&~FOF~6{-+-6r&^x6oKh`P zr}nZwxl*`5V%Ne_w|S*o)p{?*I=;rU zn^Q_oNWfn4aXgE%ay z2^P1`747D|cPIBR@=q3GUSlL!Ycx*M;SBCn zUGD`*LNuGEq_FM%`fAocH%nKv4H)edP!rZN1jVz8sw@2vGKVOWR zM8bcFrF$MVU%mbDzry{4zdt?LXZlX{zKy31W}$!&U!&bxyB`$x*JvY}1kT2pE&89Z z!Q4_O#$67~GJI%M7Xn^IR80b50-=Em=_na1>tqxh&M<`0T%o|MPDG>WqDiEqUc-g? z&)@f7{rKXw)E<>>hItiAIEzyjcP*!(MT#*F&?A=?>XdYR;|=t_ zIXBW!jyZ$~aYjVEwWUG@i)B+#S#%biH+*SeQ2n;S`Zwrnh_wMp(k;(aCM(NRVRDf< z{g!sq$0|;w`jD9~v1}YBKvgBQ+guQ|e=ZA0W5qZ6Mb^9$H8PK4RTo=lQls4I3V5z- zvHMUghm82+NIEKVY_`ekQYpa`*92>zu~v6sQAQQFf(AquL;}HE>06j&D{4 z=^Cci&&D>?xSE|w_bby0uynhP)Y4|B9UQ)iRywORl66ih<4oY#MR_RF`S)P>cF=qG z-t%fQ<5#;zd`dhW95aj(CNr|pI6eiB(i-!$z~-GM{R$~^w4#))oZ1=QPP%5nWoGRy zJhhfAixSjb;`~4i3yt2raXQovrjt+8ES|q0YTax{-kDejbDBV>*)Nn@_X3qk%kKY? z2V!V#HELBVh+uTrE#7jPlR+7d*P+T8kU!S7>9g)oXv{e9BuSgYW3_{ED0F#>6C_^2! zICz0hdJ}xU_y{|3K@A=}2tHow59SVt{ku!B=zyn-49Fw2oa8;m=_!mNPVeR1u4PYd z=N9&qbbng2dx0G0{&*0^8bBb*N5T?C+U1%_zGTiOwLIij)C9-Z*f%lJz)rq?`r-ii zzO`=Wzpa(zX(JGhn4ujrd7RP_a#bg@f^HO#-@uDcUAEZXa z9b{C<7kTXp4!<_sMl<^gDVZGyF?Nb;i)@RtynZ*{dcpzac5-uI?^fi!<_ZM2+~-0?_x-5hI?SA#1-ye0O)n z!))BBdT;)@`rm@8?HY8!)%xG9JKul5W$S;px3;@mH~QbN@z1C2Wu2Cz@&W=|s%I7M z0sn}pMke~VqFzOo80GSD!Or4RR2`lF#WlZYg&{k)P`CzdzeN z%8;fp!seYqCZ-8GTc)$z(f)C{&JQALU;q%Hn&1Q0<3lal^H)z%oua;>(RN7WNvX~! zX*12D@XZgFT=StFd@xi0evm~@KNRwTVpAjS=Z6-nPL9(v%K0%&;~Y7svozxr3LgrB z+y}ib3_e2p9GZL*8;7M*r<9}5C>$?~v?P&d9Y`}n3M5>I57gNzZqWwv91f($%O%n5MnjPv$2gq2QS|2_wWXdqiFy=MTmKbudH?+ zY+yj!6!TtHey4NF zEa)N%3nmc|7U@00rGt`>G1g~~ z45g9TrBA6;YZ6Q4r(b$`uGUFqPW8pRTP&IR^8L?CTfTVD)m1|3cTSGW6#C>_6;1TX$$AyzOLD$YwQ>(Mew>U!7W4$l@ZRG=XAXGHY51=vPxx1TZ}gjSWC zLs;SGfXFW#9Srk}`UYQn?K1VVrxfn)vURifq=2TgiN^+`u}>v@_11u@Pms{SVD}|0 z;TB=>Yp=3|8l?6} z`^NHLsWdgu5TIPjNwx}4*wUSh2cy|gXsW{#SBMmk$#K&W(NOEx4s!N)w7h<$xEYCT z10Xu4XIPOUWo5P@LzW3+HMK2%q3k+zpNse5VdfM4*dGHPM7Tc(aYJ|g^WZEKK?%uJdJ25_Ng~__tSU9tC67KlXINIzw3%%Jsh@t} z?i-l64IS!;J&?0Nizi%?!w;Qc|5JoU(OzSHltQ%*M{e-poWy zOniBhRhdy$nQuj8=BwxVYW)^V{Y>maW-ASgwTHpi$Ds6xB_91+OWH#Gp>!y~4gFPl z#uZvhelm-_)yB+i>=g4)+&JCpCbH`{t%2U31YE)=Ly-XBrobO4DyK1e183%G zvUvGW!Ls$!9w0t^`O?I$*7mhr{3CogsSPaAgF?9sd}|7K{>X0tEA!9_2$3Yd`ZIy4ANB& zY%fai{#*X$QKx|ZmA_$lu%GB5?`wwkK67<5z2QlUV!8usFJQ~?F8SlWErA;fE=e2u zh8-+xwu4j2lsT@aQ5dZBsti0!k4ntW*NYJ2;O5Wvzq2fdARirp$yR~rcDoFaf$6mQ z$bco5-fsRd#y*JxR48CMpmT8I2UtYV(XYanE9@c>>~0g$RwvEhCH(YD(DNzU3TH{G zKo(SZm4bAfJ$0E6?x*Z@wsx$W19@%~{CgmHKrjRMIBM`lx+!a%3uoR^cL62~Mov?E zfQQ%K>*p7q;8#F(<}1Lq1b{rll*$<&n4A0kuzTew<0Cu%!c@DCVM@?}|LMo|my3{% zqQl$cc4Q1@aTCF2$3?)lJjhi3Zx4KKms=(O8hpn~9fJddK@RD71e}oAl$>7&QtQ3M zPuiNnQ}(OZ(5Z0Tcg6;|i43Exai5MJ>Psi(s6A^xPC-`x_{$bh<{ugws{@x?6vvQW zPA|ulo^)BUzpK>MZfOJ|3yrK<2DGh-D}5dQK%TaxIxyZ0nQc4Y3<+~h|4bPkmXf?_ zh-%*#5nlurE}!fjIK9!ML(e2PR{AO74u;tE#iEyO=)iQdzF8`Ccj%cyzi+H|>^}jW zFV|b$j=uo_nn%K7je7>M8`?9gCnatkn4IA`O@hyO(>g=@6YRPs5sBb5N*Ec`hZ;qQ zLMYm<;a$$aQ`!rR-Z7Nj8lmsW1r0HG}@DMlrO=1o`{2KqMM>O4X-4Z{XHv3 zyCkc}#Jgj2lw5eZ2ZYb=aXahdHNj6DTaYkuZTtho(|6<(6S>h&pn@ZqZ;)#ow1T;V zFV+bZFrl&e1+-O18Oq2$`FaZ$ayE$|+~-{TlnIpK#zeVW#L48o;KBz%rjvf|thy(R zHTv0B{4negY`6xrg&_yK-y2oA_>P*q;80;Z{R$~L;DZnLP9zQlrzm5ar5b4O?O2$C znwWQ`?b(_n*#q;4^NIY_q-b>WvO9R0rPVZ|eRSD^a7weeM+0g(*MHZg&`!B1jIwKO zz$CRNlO)8PoS1QCQ5W;W$m3NmNP`~0lHnUs^AX0mh5|odO|T)M4jcXHFz|r|&&<#e z$C3rayG8hAA>6fw3{BKGlqwDIydzFUM2MXNcB>_xeJF_MVYiPb@lB~~f&7FzQhB+6 zc~gdAAVw81;QdPVskr-N8_UOthuT1s#20ZO96vxBd!u8}tKMBz+3N=K! zkQ7Q9Ged3&m46e%a%;izZEMK;KR;yeKRX&B(wlm}zCXkY3qs@~)^qmgz z@AXG=5F_biUxp0Y-rKW|$1YGG%X7;@R>8=w?xbDTfDZUvZPjqc9crM65uMHf;q1*F z^I}%fF6I7gk)LHgbyAWPO4lsrB7VUkEI9B~1fEpFiE)pQ&d0bDk)RxOEllzW8e^bJ z5-(F&n1!st&Q-j_QrOnxWHJ0kuP4F5+PO>|K*Z%08Nt3&!)UMbvEXK#X1JOH4!2f+W5s;hij<6hZ?!x}Y8dC|6x z>gn?{$AYAW0#Bpz3cS`7YG*4bA1VHNL))?GCot|m{9c)~I7ZRCZdvi98B2iRbVEz( zf%DkUj?bVX1giH+5&IpVwnxOh$4kW@CXykm01-Cmq9MX8$^J`MU`DLa6z}d-7xckJ zm4djCyT*l+QbC$L`(2tEErfj*aTFxWV`*Da+>R0~va?WrH{m8j+c(FN_uW)a|f}4{~ z7p$9VzPGfU_Ehnl9C$DHm*N(66crzfjY9UO!w+8 zr?5E5l(c|9EGX(S~=L)JD8+is7gDC8=LhRZZO>M69<0m}?Am$iD8N&dh;eV8oy-&|6q9fTFX zBa?mZ^RQiGxP`9*y&cnAghS{2jQvIr<9;Kaos>qv4Wap5*8et4) zN}JPKefRW(OMl<^@pyYe;u$42^&dxhUpDIEo;k7cc?#tC8=fN>QT;mw%$W3i ziQ1^*2B=}6_!Zc=+K1xM_UsrYQOxy4F?(JGFsNuv?Po>JnY{6i#^#GOWZl_f?Zy3o zzy2`9gG`xDlbvbvZc*cgsoJ%oI&Q7fK&jdYJP-9s#XYfN`K(MN#*MU7A1R|863&vZxa03T+TV;G zSvr!COf!JSPNgtF`$o4XDFC2y=!?;gFF(91r1u73>smLP#{Zi=n#LZEXuo_9f;2A;?FyXE*Xi-!;MK12NooDYi8B@r06-g3%&5#1)1290`soH$o!G~V(p-OaG;5xxYQwV zPitVaZ#$=S`9+aaqe%7#)jJDzw(Y5>^Vo1HwLLrb!0d2?J~s<|^QZ|=T9iov0Zs+u z@?4-9AE$_9({Fy&&Gd+I-6OX@&d8vct9uzv!q}0sN9tGjjxLcT`iF+0o)o2MctZ*h z`-lnI1MZQ}$De3Gkam zl$W#jZR)vVlPbZI?ewOh1<&9!jWoPiarZzZP4|RYvlTyS@sRZS!>KCV#hy-FcAPP!g-W?^GI5jBV6RyLfjtWfJ^{fYoV!86TPEPgb+xjj)9CoNvN0`DweEa0@ zVb~qYnxJ!dk8I6z&WN3m4@VVB@FdN_#mBL_vqjZk?k=I8(#5NyQGabEnXz!Civ*fW zQvg`IHTTN;*RlC0_m38SsU)gN|Kpk3$Q>rd0mX0&Qb@8^-fv)!rP(x>hMqhTG4ov9 z)-!X0qYTh#nQDkE5vWmiFs~K*d?v#gQFOG-t=+u>BW*~e%gqQ|iV|TA72MSu&%Nvx zGeX^QSfSsOnKWWSta`|0?(E$9HNSJ=I4KJ2KPkL`4b1dU0^7(>aKU!WAhgbQzR(j6 zGL_yd0|-o9nFNWA7+IAWZY)|*M#G7OCbkdq=WOo1g?z$7SR51}G26zhI9oK~OK%El z#MlMDTyi5BdWUC5wSu62Gjs2FI_UJJ3M*2+luQmg2axA#rxv#mwF8^2=9nztL*k!>~ zk!e^2ssu#U$)7h^wRxaBqM6Z-@7FcZAE3@6rGZ0LA_ZiB642k&`5>vcmtc%`lPpM0 zOIdYVbHFDO1GVwHdPU@UD2nB3QOaI(cjvXYlTe)M=jh?Q4RE#uh5Wxjz$l!|Cd_&; z6oRAZ8bhH|QsRmjBC*p9_7FVR^usBkKoeitZ9BrCMGgKrQ=I~pM+1uhRe&my9@C!u zMwNa0MltgY;d?Z$@q-dz8nD{MS0g-X!cdMsjGG+i>>gZm6I>;?EVpRx=;}WMddMpT zt4p+jjNT!^IHfbOuq2vK=UwOev)y06%=xcgkK^@EbX}jd3qyFiJ%Wl16g(#@QP9?x zf_6%Q?x!V-MWV#)u(+{PV{(N3|1heLkjVof49JJk=_BYn)lhla?beE zkPq9-AZ@TG2Vd?OO7-bC!wU!_ToyZqP`r*_94fm(?R(gKr*nXAn<5N_Z@@o292Rpp zyMECQbqg|@x^($785&niiue6pB z%9BJ03-#c0;Z@X0uGuo9>%*rZCPh3g$ z0yq_xkTCIa&5!j6TI{Xgn@OPwh7xdbGh>WSREXA0g%7V?iSxVL8(7Pp#B#$f{;*U@ zM?!;`!HOkkL?S6SoWqW!0+YrlunITJVTh-Lk7?>p*4aF_gPp=? zOg?>{LD5JiGb@rIN{75W>P8OwxfymA)$`*xY@l7-Cw&3_q~Nf{sS>(j?DlW4)=W>T zlenCQ&aHDGVt9UCGE5;`Q76>{gIe}r#N8i1B&mk zB8fhEGP$;oY!yk#QwG%NU0!j{Rbo6nnHo$ua1L5Dp#aM$F!PXwpse&iy0_6v5co`h zAcNXuK|jFKPBVyX3_5@jOP(4Q1>^+3eg66T04jFS}-T9-g60 zp=>EC_=8-SaxANsc$0wIh{AC7N{OQ8xS@IJa=ikTP2dnIm&szR{9Y?ibBed2A<9?OFd>NB{>sfzd;uP zUPKt#M*0$Ie6{d9@Vp$ymZClJxUj2~pj!*j^!@h>9VyI3UR*;^qB?pzPrcB_f=A- zcQSpD#O8da{2rA4@RkklXewa~C(FG*>L-r|b8ft9!N0HMM&R+{9uEHLaf^Oy7`W!M zpn2+{j-7)?jhUetV1W*-4?R0kds*CVH$8%Lqkj@fD^__O0Ox0NX3qP8?)VAKhT8ID zbQeL9C{)6YF2*(b?At-e0A35m8AukO0ozLi_ zId(aY<#W`@9SJ{J%H0{`H zfH~X`{yIjvAjeOTeQ)t&3~m-3qoImWvDL-Pv$7s305-`@lr;gpGr>3)W7Cb-%-BhQ zvPkSt^45`IY6;#I{#GQN4c#swp^qBSc8=wP3wfI!4Z;AD6pXt-UjbD> z6f?ZB_$(Xx5OTlQXW7`7G-XFzK%jNhBiI>?V$>vXQ_+N8Hy)*8NktGN#!~E>m|)BL zX_z8^)&jCk$?o~<@h|i`c9C*uLwT8r#DFo9?5=QdJCQ6iqlL>+>dQfJ#5xjg5dknZ zKicX?R&~%K?ciaY5s3bUfoM}cqP-4d)rD*dxUrS{$@C518z?tt6)CcJ4*u#_%|X;J z*Cggc5GP@mU^gzBT$t4cxljY0bzmuGLr(kK28#BBAq8(jOa6p*(8|R5L!f_T;7s?x zoP&$gh`X1f{&K8v{o&iJ)kcI_cYVp(5(0ns2Le3ArVKWjxe!W?$rV^u;yXm{egEl5 zUXzfy_@=!JBOdBJMsVrmOWXyCOEG}IY}~bw&QCNTN~Bd+1=+xA>A0d1~J7g(JoOl!17@bU$H7JK=!P}4aD+h*F9Zv`hQS<*ME8eC&gi=2bZWDNN>hs$?3 z%&NAR0T}m1uATr1TK2NkKqp6ljrAU_TR_Jh;OpYmH@p`gy$Bh-ivih$&kP21q_$T; z_urnI-{B^SwJ``@feEc+rJ_5lEaiNy)s_NfttEOKHjEVnC?Kn3gr%5y$?^Qjj-mUn zJ_Lcvxqe2$vOGHL4`wva_0(*Yaktupppv55>%U@qasPb{ zHdi_mP?r68W>0vuerma0tTKypCuawOfywxYVyZA2qNJmB>||WmsS;BS=IHDe38#GX z#tnoPds!F42Ae&QtI-8GdRqDCzo|ktU!odElie2EB?1Z~ztW)NKS_|I&#G~Cs7OXK zXQ1ojxf&QHvjJ2^0YFSjg)A-PWssQt69-J%UsVL!6#>8$*IZ`Nfi-Da0ZO&A9JjgS zMP~scCGdw^D!-L$BU;%R5kc}j9LK?tc@zg!?gX9EU$U^9|1?=tvrfDUbBF4~ISAeE z_Cr9r1A1Pn@PqbdL^RSWkG_&YCV-$-RgrkX$c zH7^`|CNd`WDTrF-!r9GNFl^q+I>V5kJunm1LjRRVnomZv+j<%j3ApijFurD4(?yQKkN_iO> z1~xU?O{otTiQ2pu%SkT2FACu)h&nE9i=1Ai?54Y9BeKHm&NU#+3`Y-_4AI2+luN%hX647*Hr8nV>6h2=+c(B zpAod4?v6V9JM3QakN3zF-};QqO@l(-3UBn=9O8VK$6smN{cE~SPz|9 z_Kjqbu?@+sO|2uy1<74Y8^8gQDFlV(*4ZZ=J5VnjbKERfO-4RaY7Z5yOhgEcb(;E< zao_$6sgAPHEwO`joLXczi%Wz z06u(OW(fJCt|1?P;wQcDHU>ijKWKp|DkjD^G>ZqV#IAfiXHh0`9hcE~(OGYrIE8p61TV zem(Xr2}H!L{4PEh*JIBdu(n>}+)5=@ARN+x;mYMmHc7Bh${tVS?vRW4RQBJN?13 zF3TtRrF!pV_ccip{1YXWY)q9jFOfTr$80~sd0*K$1Ni1w_3)KD^;2p}&)FQ$GB9|udcDQu-(E^R`zD42yE0T3qrvCDfw3A78)z!D#s2Ot=O~82B|>$L*i{*MeDmUf-V8O*_nf{lE&^7! z+vfn@$-aqZx5&?&Of3MP!uYH|6_}eZatv|#4=A7*j$QcITJU8?Oyw0hOwbvw!%47MSJs^L-L370J!^RfsZnShZf_ zN%(w#F?Cbo0Ofv(3u1YdNjBSyy%32Q{zI2O`bI^dNj=3}=Hns2OLjb@dWV{a&3O;80BFf-&#mHI%j_Rt(dMT- z&(2PFIp9;}n+w`K9H@%za3OaNI?8I}af506R?$+*(XkT03h5eel(fxJRWlkQ_nPB2 zE=KE?$Snqi_;c%GPsx67L9HTd-4FkXDcSFeJ3oN)%)4>p42Z@&HS}o=VNIrKpw&?zG0sQu=HSkLMge@F?x-mYTed*s8Y1Pz?M_WjBZ^4L4uJ6R= z1N=0gyV`SShdv8Xot^mrxSHveTIl8#LK0^=2bD)EIbce`%z;y3mKZ^mB2W=#9-9k^ zSu&JkHco_jSB-Mm6R+N%mNY+@3L?Cw{4y z7^vulZAzbgZ`o+cm@+qTwhiML5ut1}Ps0mQzDo>edAljqpjsTGA{T2!{>iHs(w`@n zR{UjXDF{?k%~GH$bJ)?do&!j(uMzD|^p>L{Iq68bkz2cGgKjHHQ_@%7+}(A2X;{+y zzPM_rb=QxeEhK!}aeU(i>^4212fok><-R-t^)Liy@vG_~Y=3AGE2y+V8yz4&cWgd8 z9>RJqPKyW6pu`x;84&TqiO)&;VzGG!UvB{0EE&^FEH>AJ;hk^L4)pPtGA{wA+^a;3 zj1azhvgcILENszl&2zWQc`hY%n|5`N^WWUVQ;din8%yc;9_ze@Tu+5Q&*aW`xH7;&l25`?zv-%HK^4MoRg^%|Nv)NhPmcs{4EWtNI8KBfHSH$s zRSAh74%lzQm~qF`sOMKnEUg6D&dr93krz_yE~QA)f60g+%{w!B3OQE$wOE$q4;B|X zmYLacW<(1>{P0dMCKdj+zeiVhl$F+t{=@YZq2)XsWqsLVawhtDk&f+ZEi36HmRz)o zQ!Ot6iO^q|a0a>6a)a_Hw~S~VhXuIm~fYdgJWL8n5HA7;ZaOnaslj_Q7Oa1@s;AtOV8*OACx+*+gl_PuxD>ABjw?hX-=!;>}tzZ{KT`BMYb^QxI zEVM#P+orYms9k&_^gF+scfg2Kt^0sM+MXSQ-Qtmja043ncvJE?wE7;AJ~HfW>SI0# z@nNiiMX&wu(~j3Zft+B>37k^jp#!-Fb%UpBF}qz$!63+VC92b6*6E*vS;%x}Zx3QI z3%NCCz0ReMAr$1txO-(o-~h8Q4(aV%JusJVg-s;m&zd#~rb>eWYFV5V?LS^SRyOfd zzW*c;1ppZXWpg$c4JxQm$LwvV7{EcvGQUDe_+Zvv^iwaUkk82Z8iXM0U7e`Zt21DZ zHw&e7NsP-RUSg#VfLe15)7$#`U?%OF3YJj;3eFWVJ_e17N#g<~_bLX5eOMZcuLafx zBoJH>F8Y#`W~`Ec=<|FV{*=V=sXFP6(Y9`IAI=$1tu;m;htD(L)S*3 z(0qq5vS)6Ah34ixP(soW-ugCO`zLPj>@rydhJvChbR;S%+_Q(;S@u*(BRS z5|L2zQigXoZ82U?8P5+Jeh>Vj14;|IN94T?&*9uRZ=SNIp#%^mKGBNbmy^WBih7;R zi>Xrach%0r2;*HN)T&+@v!4v$>(6RfdDj^9&(+@4%V4#d`#CJhT(2%$q$(Xxbe9FB zqd+a`mhRs54>py>um`Fgbl$@(mK(00dVlZCtX8o0D@k5eT1>c_1}6}h4Tn>m%2~cX zl^dcf&gdGfwmdeh4U=Fc=(TCQp5W&Suca75u@cO+p@<{+lV+n;-6maehTYu+=$E<_ z8>^SQra9H@TZ6B~lGbF0g}-m~8b1WM1*}wShYO7{3lj{cb>m;rJY*D%|r?*M$~4~1Kf4WDJ>ZwHzYO#>JRHxlCRPX1_ehPxw- zN(agnda1Be{_S#e(($%Z;p9bjnW`}i!zfUPIbSK3U zrYF}DJ8mUUF~Z8IHvB3ToPzGW!jJx_e_mk}ML~A#2Mj626JOD8VHxO>hq3yguS=ga zlspKjfca~`4RC8;LA(m*xaOooH+obqI>=1)cWH!Ooj>_(0BY?3OO=?lngkrmzeIYQ zyS%s7MIj&gORf*16)MzSR*$@3-J>*WhB_iV#N*49+xoYv7i890#J-%;M_uYOG-8_=ZZ(!)lxmKqX(A6BLY zRcSzI28U8B3|-vn-s{35py@vPFpX5SQPp&1toUlAY0difp5oWf{!)K$P#?IPb`+kd zjbfJX03WNNEz!9X;p$n*SyR?ADfX$2Ec>qU6dTSQ7hk--4Mi^#q19U_zSGm^Hl6)fc$OWyxcGKB~hOE zbG9mSbFP2;wr|M8*}WS!^G^);g6wr_KNV#u3%tNo-CVuxAqBzxC#KoQ{v7+sk#S)2 zW9y#_Q6!3%{`QEIRI-jrX#$DyFL6*ns~XGjlN#1Amk9oRzz$In=mI~bD;G{ zr(BN70`r0_TUEh$!K?>=B{ZY22E;GxCpB-5nW7BCbY1*HwLLb^7+$;A2FseBa~W5q^ZFOgNXd|?#G$JiP`H6}A( zt93u{Wwy9t33px3mX@$SvsYI1uft+1t#XB|I00Tfez0!&+2(2*Fw{#Av&D_X&(GW)}#9{MVcD>6QR{`e{rWN zhz5%dx4T^VUU8cpUk|%uSoL4Hf)vB|wIOiMhjh}_7z~<5m){IF8SpkLP332bk zmi^9dN4F{i48?;g$Ipy)q%D6;h;@0WC<18}C^>0Q$U-W$TgjiRjW%dXN$P#oJsFOt z;k243tkf@638qIvHShqE#qSa9A%TxvOEw$-m2gs>ylA$^QO{wyDVcOM+BX1aN{PC! zghTS>Mm0X+XfxNJD*Fb>jtS@cuiaP_Pr*Z7#&vxe-;&|1R!)OmKgzpGPdb~cN6=Mzceqp!KVAklLU6Ew}eQa6~t?*&}L z<{_aqB`|ZWY<+u%T0B@FQiEGXbxs?}GKA|M_&|?v#`EjdE)R1|i&T=YdTaA+9cPFD zEU4N}(IU{*u1gYrc=7dUsM!r?4AoFl0=(OA<7k)rD6U+7=0KA`f;DIL8EHSg_#bpX zY8*)do~(S(a`vRh5J?Qg5(9?;v;A}Hi?(aFtDJQL&T+Vdqp-{LP6|fSuC_~B`=w0S z6g&(Zw6lh3Yodi#-E*KT8OU}ec?E=!0W{mm%H3?S~DYB@|e zNiD&{?1K1*5R)@GtGRKHj}O@C4P1WNyLGt+^m!rycJ;*AF#o779hRLQgys^>sLfzv zj8wFiZ>o$QX>DnrL^0va^y;0rRhXU+hBjk-NRLH2Klhy=ZC=Y}yoW7S$*}GqkQ3m= z7X^LlLrrZ*bmY=+$S}Gyvfg7FqNOK+>r1O0=L_G>iyzCv2gQ>BOtC%iJE3jf z9vy88aDG6$WQ@w)$QkRHiQ(DQHR2*H14F=9;Lc8Uw|n!;$HI!`O`r+EXc7o$#aoh+tJeZw)|cqrY+(&5oBE;BsxCKFscD;#?6Cv!TKO zSl%EQZlFSj(s?v>xkR1A$}3b3MX0*Q%UYywP>1~54r0Ha+1FQyukhYA~XdF9kSI>bzyuTiIZ|sgEyFEHK*J1oA zTCy2BQ6>OB)6p{Msp1FkIZ*FLKN8H^k3J;t%A0t z^ChVLvso+OE$Fpb#jLh9jT>5L{Iw%Lk`7KCs+SQyk4pY-0vtAFsj`(Q`J+d<*#HKW zhqU$GNQzv%rv|Tp6;WO(N4=8mUW3SzREri1FLg0o?;%p00yyV{oDpK}Pu~&je;>_+ zYC>n`-fXi23uF$B4}X;^hmZGsx;C4#rn3bugqkiR_Q57)_F#J}+Vzex*@T{at#>=z zgL)(mhEI;q49BA-M+V6Vjm9OJVQjCS2E^fj6F#PVovUgZI zrbR26&-_Z)>!%6pLDko4YD}%?M*haEiVTsio4D$W2fc1-&I9$0(A{W>17-Xq(es`T z+z5KR1Up6qSZ7EnkKzT?N*WyD<;C=QtXbf8C%foz3(Ww8C1)e*eQj~(HJ|S7f)xc* zt6FlwSr-J%%lCC77g$VXsiza};(gCyGP@T>7Dy4Nyf&TV8kGBiWMR*PqOUo0`8JaC zGjxM{93t|~+tH}-|B2nEN(L<-|Kob!a1as~?n{W#Z(#}|ctQ$OSfTw=o{&!gTB1)I zz#ucvwVZ2`&Nmwfwq6nkkBGxX*-MCMr~gRKhy7EVW%R@i2k|UuaaBazUsYZL8Q5$e zNryh7r8`7eSI%RbiPokvrwXqUh=p_M%5^>PSGaTdE~U3K!|ZC}7#G8t`GG_yQu#ah zPSHw@6=#m2Uxf=8C5z>kjZ`VgYu*54TRF#4APPEjHy~`qE9Cq*pAIb$8vXymuGYJpMQ-(aYrg`i+_*bUCXpRp9CGBW33nj zPSFQiYCGU{t=)^i^An>0VUS8NSjBt0W7!lxw15O^SpAH}*-J$7by*?mBfDl8z~&hv z_5@`O55Or8yUrE!jO4xl&r9f|Fjbxq7m+W=#mS<%CCTWPi)WL#wf(jSoFjPJp5-m~ImVSsPT z?DQt5NRTPHV3BA`A3zRP^csZs=E76N66&s}eaMRLwu*chd6(re*gz zBMpZK5<*KXAcfojfAm5hK@ zi20;~Fr(`^{`pttqe0$jtAZKN+#js%3i@;r-l?g7h4kNQx=OO@u2$^XP zU_0TNicE@DY0YXus|g(Z&?1>j(5t2$EBxxK7+EwBU9=jcJl)CwvgE-gSE_Q(hzh>B zfKd?c5xqyh51UFTB;_Q1eO@WGTL689PnRlO z-##}rO_|k>)wP&BC)zmm2d3AM_7MRnrV3`0uL_$&U^(6xHMMXz zbg8?AS=6GZJ$bt4`iBN;B=VgVy;MWof^utt4l_nTc<*>5n!AEoZ_L}`7o0*v=fj1J zGhH<=4hd^gZuNlOK{GW1jz8<|N$xn*;F<`RCEES4+JPI8K*6O~4u-QmzT?^A@a*s! zj}rXEQs=|hMh!SR+=LQ~U+o^<<+r01F+H$?!c`yXH-t6x5Mg@Gp z@B7x`T~`LW-}TUe-Kh?L;Gc}f48V5&u`eqdxlh%4xv0*oPXDzV3meE4kiSjdT0i_w zh?b=JJnh2}{c!)3m1HQ~9(>_CrSPG9__;vf0}aD;^10LP*m{u#=-jIII|EbYS|01Z_69+Gz)?8(s*C-IZw1pIeq0n& zE^M#jT@d&{4`jHIt}8tKLfm{}qPwiaiJo|-_NBy+Ih7qpa)ROee#ksAa)ulleeS$h zf}SU5419V%-}GI3qw*xDnXC086+*z%y0SGviaty%4S;u9w_6e~&s&e1ldt9%Ff_q+ zNRwZ&q5V{ESV{!}f8#`7X=5yXn`o^@(u@!>2-Iv);Q7VG1uYBVy5qjXun^Op3A$&dSVy7*^G z?<6T>OA&$`WOxP_gx+1E5}$MkOqliO)Tp@gonqQ6tY>3m6Y2|QmII`iczCBXS|dPi zTS4{m$%m2xtE;R60?e~QSk75^qgfJ!7Y6O@yd2&GL9=hxw?08*v&IJJL&<}`SM*-w zkfI%A!u>03`j7-)@s2TLp#u#@)qOA2(kyFVNO<1SKQ;iY-i4#5Pd?t@h}1%TvAjc# zMY;Y_`|b-Dd}};VJ3ZT&Zn*q!NA0A2vnW|bgKJdmHa{$%cQQ7(wl^$CB7Kn*`xJsS zW>Tdtg~IEGZxD>y#wIzSq!LPn|4sXH$MErM)beuwXj&C*U^ime(-y*I^ayt@YXtmCg{Y5 z&00ouA?)y*P1<$O6Qj{ORq5)zlUs+rcSA9rV@2?Bzt8MS2RW2}*kzgufGUGg=ueuZ z0&;l#KooIP;Z1X0XaUaMGJQcO`nE-wr#yoeMD^^c&T-cWVFYmUPp=RoPRIYOA!|LR|9m&J zTzhuf;{iR%-=>Xd=r!UjkL#!3lxv>x8ywD}rW&ls5V$Rp3BHKm;SRC20tL(s!<{b! z@zI35ZhsV&MO;5@q~nAP$zH8CwA6!oPkUaHdFSemh+$=|0?!M+fAlV=i5#0sfuhVB zJ2f=X$FyZBXRNcvvPl$L?29}4gFiLwlGEz2E1W3uZ$3PJ7~2#LOZ;m z&FoUMu|$p^U~!2CQQh)XVQ7wiS+RI~Bf0uRsiJ1|MA{t@Z|SmU?FS2ber{dMup{M) z-&%-e0{PskmV*ms)wk!$e%&@3%Ja2=ba{U$M3iWM@t&`JRmbyD7T9Qir_@wva!`zWW7!!1D_#=$?7Hw~D_rZ+gYy<(S- zbf`o#OPSR~ha-q86{_Sd3yql7l_}=}ur`P;NH$;_EvmtsY z=xJCN{O73%3);KmQSp<_(YSq5e_Vg00!TJEWFxf)3h9bF9%A98A$N@0c4X~AB9xh? zp4ShMHd*6m{cCuCCQhLe5Y+-ZNHOxTF)A<0J&_=)xJ02nmn-vG(!MDk4YDIqunV9|Lv~wItxEWOHlBs8!qwWDgFcB|$f$r~b z8w4f3mCPNJgp)?joy|4P;+;Hf44t*rwVs9U&c+3FQaQ0XH1>OuX&-o57|RFZXo2Ct zHMA!TF7ML38$4q>cL4pzr@+U!+e5-`nsDad#P#C1OmM{+l+v&a95sT8fr- zL1rI&Eb$=T>M3bxxb{6f zyK=Txt}SR%`jhKS{L$iPU@Le&xj-m+;(~P}`n7__+xgw~8)q&(;v1xPbe1=kUNIxB z%{W&PE>pM=`^P&|y_voM-OmqSARr(B02FAxhj{~t73$~iKjr@%2^g9g8(KO#TRSqi z>swnfn0ov#m>SbhVP$0n`mg$@{C{gE)?aM@Puu_9|BIE4l?{l9>3_jk{)bmOJ38q* z{CwWk%-GoKf9U=14gY`r|JT(1Uz7XqPyTOxMHmSM1a=ps1OjRt$JKx)2>1JeYgk*a z?0Nkp7c@Qlt+Fmp2F5L;a=xaO7_nMf<3L(-mW7Fhfmtjdp28l*V2ww7WR3S6h3ThXxkz+UXCwGJaHNgT6 zU;P(mm&d8xgbKI<&4+NG6RjI(b$cztK~3KxUXL;GWZtZ<`h}C~UZa!HGz{WNlzPzO zJhYWXx=(ky-u%orYPHd?6`0&0^Va7*L}9x)N{Hy)5?BEIzx99m&*1(ef&WP0KN9$# HErI_A|5Tk@ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeBadInput/cdesc-PunycodeBadInput.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeBadInput/cdesc-PunycodeBadInput.ri new file mode 100644 index 0000000000000000000000000000000000000000..dee133c7d2ccf9f927773f6405feea29d37ad665 GIT binary patch literal 502 zcmZWmJx{|h6zqVUs9zEw$^b*j#MEYfUQ+rYWoT7VI%SBQ*ljHwJF=Yu{~jl_0#sRg z*3&!Ro$p=wTNu2~R1UCGx*%dIh%w16_v7GhUCFOpQT9S;EX&FwK=VZ$JWnXq%ovgh z1`y9y6MzdSMh0E225k_wc9)8r8M88)hfRnBYCan*hs3h8&1S#zK*mpNP z{>QF~CVNfF1FFYyFlby2xfybKB!bgXEdlLl#|4XnC&9BZ`Sm*HRFZL7X*SYXgA5~8 zaGM?&pztW1V?up|xEa*1Ds99qTdDTlDxowkeH?6Mzz{ChX8MMV~7 z8RpHKH*a>57dU>pQw(6L%!eT+nNq7NvU6i$Put^Ez6; zxQ?rAzO|@s}m9B-_AwfqDXlV?)dLqfq%?SexH4!xR>|^3c8{2 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeOverflow/cdesc-PunycodeOverflow.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/PunycodeOverflow/cdesc-PunycodeOverflow.ri new file mode 100644 index 0000000000000000000000000000000000000000..3f18a582f19b0832a5f972ec946141b47a466668 GIT binary patch literal 523 zcmZWm!A`?44BY{x)dom_fCC&#Pe@3tXZJG1K+0hQF?Q;qN)vBHbV=o;1OA?LFabi5 z99e$$dw$-D=Wy~gwh~}!X(j60S~yo6>6oX-kFEKTR^h`MX;IrZ2JG&hrY?E|FZ~ZPJjHLFRSG3;oeT*T~b0T318y zv%pX*BZf^&cumy?nT_m9`|<^a(q`$(1=&^UyJbteD5VVy#=Ek@;7FGDvwV;hz0He? zh^KwoIoM4q;v#}U(^j>Xp&r40P~=g1RGW0SA-xtJyM(8E+PL7B#BFQ7+ZFP?P23N$ vSFrikzS~a5y9bzsdD@yH*1hc8xZbxYHag(x$-iTT`S5{cwQP$m7tjKJmSb;&tP%Dm;X_X&{<)(o#2(-l5L}XE* z=y>jbzTbA#%XTbBHV_Db`Q7&&@Ax?0{jH92cz(hxMQJcT#7>>rBZqYN>6Vt?)=nB~ zPRZ3ywfuo<+no45?m0wJf`M}Gw8WH`p>-Ye>yf7@Ks6c?S8OQ{Djw#-?{2d4=2m&D zyP@nk;v!N-Zy2-9g zi@5?se6vR!HZH{qc zBQz%OY=j*L`GUf?CtY+V(z|f}pCJ-KlwiFR*CKMt5L8G9#Nc8;tpRdbkJ%GMVAjYd zWavw=0lp!K%4Os@#14F~ypCLid>=MB?Nb+nE*o)+_)4VrVIYL36pMYB!l+lU*sus3 zVTR?_m|p~;kHyGlJRTP&VU~vlmx$u|s5dDL#L#&guZPg!C^FzM4*BSl0(^>B+%JCW zb2jo!YXAA+usm1I9uV4pzB%iWJ<}t|z z*_ctOyr1Fh7^i=j=e4ui9h~!+OwQ+1yjkz)hIV{uM7#PZ#p7k@Or0lxsg1LaZnlrr zcEtZv3jb}?%DnnYya_6k_i5ybUTt<7Mwr61V{QSK$s9-G%Ss+6s7&72<1eduJcVU4 z#~vFid7Pj!d1H@_)jXcUR%ULj#yo|s%-mj$c?!#9eiPrAC#s>E)n@%zYiNx#v#P7@ zcDMk4PuVe9R++jl=NM{Vt9qxcH5;K~Axm)%zou4IZ8V{nQ1unH=J1(Xujl3k@ocGZ zx@o#*T!wldvgWp6lc_l$%TB9RJFh0^U1luj@M~)6&5O0P=J0E38JeNj)|l5EK2z(- zY~I35rQH;_Q3-EuTKd$2IuZ&;P_tB_8uA#0dKrzQG6_mPP6^m> z5>+9eut=eCPUZw+WgH8G5+_4-uGJ)6V!V^?^;Ej3? zwdDU={*hoN_AN?7*%cZd(rOp1qF0-=tK9of{`x%n$#jDT4gE&UYbzO79($Y#VhLhP z$CQU2r#D!T?t!#@3rz)R%fzhEHyQS*3r}4$b{-yWnH>|!^k$LCgExDRI#f&oZ@#;K zPXb@30GUr^e_J|*zID}i!`j`dn$BhaT+t?GcL(h^S=$BCIQ~H=qWG5gP3xoM0 zF$;%G8{Xt|#6Qd+911-s!k3UkZ(tdDIJ8LqEY2k)!h?3ttk+4NqcPLNl+OYVVq@w0 zg88e3QFDOZ{>Yi7_&x!#v3on(FXKUv*+8=|i`iD-3C3Pn$2r>(Z1qBqie2JEe>v)587 zhu+K1AV9r8lmHhVcdRJrZ>_h8bDHsBigWpRWV5ye7k_#V$cTb?8)dZ zm;bL1Q}2Xdn{4XJ35{{hWxXc7Pb literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_compatibility-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_compatibility-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..a4808fde7b907d1f6552f6dce6f098a1f11f5763 GIT binary patch literal 305 zcmaKnF;BxV5Jo$ow9pO=l^B@F1PjT)bX^juM9Pp3Rhcqac6^~H9G~Slp#FOtbzoz> z;lB6Y&FTZT$31rdrM)y5&aB%lE$j5jFn>)>OqM#E+y`j!D19BHDA;I8P&;H*O`lYh93 zw3V5gJidCB?2;4Y1rHR&8KoxsIf~x%Ai}IBxR3fa#OYBeH2jn2dAq37`{y~$G1>4k aZxrhobvt*&tLh%EdI$D{G!5&?VEzjqre>@F literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_composition-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_composition-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..8dad303000488414d9fb2aaf1d662c048189f032 GIT binary patch literal 300 zcmaKnJx{|h6h%9rP$&{hB?bmWCb~2hiAjy0P*i})Parh z4)>mOua+OMe&5poP??_=!--_KR@Y7bq>0Ya@@UjR68S)rC9i@alR@@YH~DKNr9Y^;wj7nlCV$qdFT@|L zP|}FPMu%J1XS?hOtfWZ=enKIY`Sg5rH1RNtaT=4l32EB%9yNV4#=1q5-@im-#c)Qs bnJ3CsdUP|NNU0tkE_MfUlh7^6sFD2w<^g1( literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_lowercase-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/lookup_unicode_lowercase-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..f9b3d13a6dd0f6f849b0dc91f040605d6edb1790 GIT binary patch literal 297 zcmZ{fJx{|h6h%9rP$&aKB?iPmCRm8)*CmlkBoFC;%9O!!;umV+_*wn{@$Yfefr;@B z_nvz$*6*-=+tUcp*q;vLiB!MUm%My1M4!otWc5f2g`scsqYPL;@!Il|HA;C5K@J81 z`2NrU{9D--?GbLA*IzOs!Tp)oNuLP-8J}jfaSfZ=NgqSMg6n$H26_2t^iat^RHc=b zl}jF9{7~$QBe0rg9mNTy()J^W$}5Gqp!>k>Pyh3&I!2h@Mxv>gzP zr+a$ud+&Vk38Rk%H2`zFTgtd4QH|6^nclk2?iv!3qd*rKu(zU2ALl}N83NW?0+fr@ z9N?dD#)>suJFmVmN`mppeTn|7a{zr*XQYh-xXK;+7%E0^|5x*l9ycD{md%D0E7S3- z!jK#>Fe>uQigOuWy)YV@e8$Z{49Tf`tM290g3TS zSLdF4vHpPUeMbX8Wlt@}BdIRamrb6zWKRPr6uk_3cxAxe>L!1zl=2vY>{h8lN|CJoTJeDT3aSfZ&NgqSEg6neB2AllB=)RDD3x!rz7A|>w z@jctJ1Mre29mNr)()Kfm(bFX2Vk2l21KBvEgXq!F59hpFHTmt+a>J3f@p)mCoB7Ap UqCTg3xI63Z$xqU>q>@4Y3%S`_E&u=k literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_decode-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_decode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..28379a151d07088bfd6890db479f8d2bb9564ec8 GIT binary patch literal 277 zcmZ9HJ!``-5QZ}pC2cYqI&^b~wo9$~ve=LsG&n;^Cl5ll&WWh3GqU88e_xvng-*u{ z@5gg@n=eQ{57Yt_?pk5EkggN67HKj>cWp_d)VLf5?4uOvOQE&Laa4^(0C6}L0RNqP zR-Rxtcr&Sh1W&jAO8M_N0L){tM;A7*%?IVfSg+tA?~Fx}K3mgd>Te-4+NsQ`U?zO` z4coI5@SJ)Rn!l3Jv`$aaeQ-{Z81 z4~fY-`|iD;-|e^N>~uDujIl^<#%Px$7N_zc_Rp(YZ88#=2;3dAkk(_~a1{Hukq{b< z;c1DC#e+%2*#G@~Z}iGeDlOOCBC(5|*O=?~x?;>3*DF-E#g4;@YikxBvCF?bQ?7ZT zdA0QVhl^J1-_Ow2S{blQ1m(uH%wWyS8i8`)kaFWL8sv(kvf%Z-*Vt#BoHW!1K`PK# zIeOi3?ry+oOy`rg$LGN?d5B(yAoE{Vg3y2> z`(xmEwrJgkf*pmqEHU=4N}2ZfPlP=w6z^5F#;#7cok2(|X_F;#;TTPlYg#3?i94Y@ w$;dG)YmyX8`Urwxu^0R8&i9|M8;!8-7IoO{##N*2Y?tbU^oo~b5_O5eCw|MQLI3~& literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_delimiter%3f-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_delimiter%3f-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..6011851c331afdd1bb6d04f27ce79c4cc2625839 GIT binary patch literal 287 zcmZvXF;BxV6ofkap#FOtb?Cx) z(&@hME|#CL{@79vP}*aI@j$9w>&rU3cauH#q);d{dejm98w2)U)!9p_l*bTcXAq#? z?n;3F+8b8w;l_FWBO?+#oH&j2-;)DK&}l>)m#`|F^f9yxxGn~5u+AQh?s9piBxn#l*_ft-=+MwF=e%9i+3nMO$C0-2dEO{i X>C4rupHkJ|o%D9(M`;>TlR^FmWd&Za literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_encode-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/punycode_encode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..b596bb4ad2ea563cd6265ff5188d7a9739d68720 GIT binary patch literal 277 zcmZ9HJ!``-5QZ}pC2cYqI&^b~wo9$~ve=LsG&n;^Cl5ll&WWh3GqU88e_xvng-*u{ z@5gg@n=eQ{57Yt_?pk5EkggN67HKj>cWp_dM7JCU?4uOvOQE&Laa4^(0C6}L0RNqP zR-Rxtcr&Sh1W&jAO8M_N0L){tM;A7*%?IVfSg+tA?~Fx}K3mgd>Te-4+NsQ`U?zO` z4coI5@SJ)R#jtjrP)!LV@;oD1FkA0edg2^sP|JV+gV}2vF_z z1;GFPEh~?(a$bMQhy+hpRxSPK=l~}0IG~LQEORG)49x=W^IjXQ(r2UFO#X2)t*p%4 z=yBs)wq-})ISo3BGfJiHDTv87?1Rw zNAK1812%^pDuBlSbS9lp_Zxf7%KL;|L}e`j^4_xYsnI%^7=?5OfbI4Tz~5v`+9MQG zmd+}K#|zkr@RcWkSKX$?g^iI8Hyg4=qq&am>?Sy_pHxw6`e%8O*r<}FCFB}bq& zjyCa=5!(9C$cKO*{6Z}pzsRwR`1d600OLt_ z-+ecm57@mQr~|0{PlNGHrrp`K$nPV`D}aBcJ*!WU zjY+$C1dmr}qrz7j0p^D^ppP5K%29{jm#cyehnk_JXfLvpqWj zFKMt*o>3X=KPTA-8f08dB=xc*A7}U^H9Gp{oVP2HZ=Wy9C45=-Wj6cYF3NMNyN9dX Mk;0%{Lnb-ozol4K3;+NC literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_compose-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_compose-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..f8f99e769fa387236fe4e46b080e61c0ae9bfc5e GIT binary patch literal 278 zcmZ9HJx{|h6h%9rP$&{hBnBq301NT_x+GGGlp!6eGG(wF`-NI{{49Tf`1d60fW&yE zt8>r2T7N)(*pURN?N5jCM5@pAbz9`gYDo&Yq{&gh46^s8EuL$oJcb|!g8=PrUjzJa zZnNeHch2iC5s~2W!taDXCkHT(r3r0Z!=`e=$I!3fwi>m;wsw>5@^NpLu Td`^vgxY+H@gjgUGl`4|?x+GGGlp!5ZnKD>Td?6N&&+-o{{(BsCU|~8v z>GZzuT`fOg^M0TnpwvGN`jJGtk=J$l5VY(`AnR!|j zIFJcp)|1egy*%v0*~(m#``fx8Ai2xGe^$uuh+q>@xm`$)wOc zGr{7k?UH?Rg1n$fdNv{#Qhz!&Selrhl^6}tTKib-Sci(vd7ih6I=y@8M@AZVPx1OQ cZRet56&KyiBVwxh`-|g|?8H?=A}Gv%0a=@2Gynhq literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_decompose-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_decompose-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..1f8cacac9b9afdf677b9a8e7a715dd9b7d244bbb GIT binary patch literal 282 zcmZXPJx{|h6h%8AQ)nfY3I--J(WS}!x+GGGlp!5ZnKD?8{X(reewIH#{Cg60U|_t` z)jj9lEI(lLejo`@*`F5UnN+vYw@vn#td^vZE0i=k3dn%H)lIgol=2vY=nVoihhqis zzq@Dk3D(Z*FA;!E@4$V;bZ6)a9{nn7g_aOvj6}9 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_decompose_hangul-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_decompose_hangul-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..bc8de90996b902889ae285a55508eabf309e06a0 GIT binary patch literal 297 zcmZ{fJx{|h6h%8AQz!#NB?iPmCRm8)*CmlkqzvhR%9O!!;+Mw4@w5B^;@^{~15?L4 z+2ODp|GdPQ9viwYvxLDb->Iiqv>u(v6;PFgsr2k3|V8*8jZCt~qaMH)nuHd#9w81)iHoD8@KPuPC z%G@Q7Z@yzYb_8C~q@x&7Ds4|e44x(tms^4c(UXnybPydH`r(|nt2(=XS^ zj|21O{ocIu_L}zJXELI6Dt;EI6UqEOZ+Z4rDR?9q22Acm1O-~udYOCnaLSm%qJS_( zO1;@~O6ke!#G0>YFIW5vdyn%v^f;_P% z9pCcohjoKPUpFPs>!-L1@>Fd5WHWpYm`F$A6DG6EMz8g(DT#Mvf~pu7d=D8S)~CmCOQNbrZ-q vh@{Zw&qWYoDtC_K_-CHo8`kk2E4_Pd8tqginrR*lnhur~d%BRUOwsuT9CNQ5 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_normalize_kc-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/IDNA/unicode_normalize_kc-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..ef9a4d558ddb1ff31e62a1533eb0f8bfcc74e9b8 GIT binary patch literal 286 zcmZvXzfZ$35QRISP)Ns02(g6)B-CWSE{Rkkc}NFTrVN&UT&PvY7ddtj{PiSsU|~Gz z-TS_GwS0&5+l~}K<-QsWN7C)uT(j&xI-^JNEE4X1x@UF)7Vn5@1W+H2 zCBQ#{eNvs^adi3%12JrGwg%lbjsTN74rId$*2Rb}_;vvgMXwFj>5I`_hJT_=D~s6} z9qn9~?2{AZ1rIui3!&2X>_zW*5MdrAxEGRbn5w<#$nbZb=k20SpI)OKQC>;C%@xIZ XdUHP?n5dG^w{=H$1Db|aG?f1W(hFeS literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/%3d%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/%3d%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f6901e8b7057c8a6eb1c13344f2d6a8a75af7b3d GIT binary patch literal 845 zcmaiy&u`N(6vsKBv|AayOdK|lo(cz$rZy)I&I%cfiVD`DDR7CV)Ja}eQ~&5}hYJ3B z?4+f@khod4^?l#(=Y8*YKa<0&b5#&>Ccj^xU8piWWS!}tGad&dc$Z8EPtM9xqcJq+ zNJxTW#i_-o?mY@76VhANIcJ3;$F0r<)ysNCh!d>^O4}v9cty1}X-|>IfByMIHNDYv zwFsiU)D4|op{=zva9XGmUs+w_>8LpZtH3T0w&OwNU$L+Ts7Aosn(`qe3uZtx8NhjS z*3V0Y24kWunvK`|w|Ezj(24l)L4eY)Dsr&<3^3Qp2I8Fz^ zSw5n>a*Vd2hdTEfB#f0{Hd`Pq9bA)DT8Yg19%ZV^3MH+xV6q&!T8Ckn2EGG(c*|cm zX`^n}0QxbBtYeWh2@pukYmN56a^E=!RVuJ{6o0I5a kd=&LV7ykJ+%L{KMKAKDi2ixwsn@RDgZSt(?RkN<}C*If%LjV8( literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/InvalidTemplateOperatorError/cdesc-InvalidTemplateOperatorError.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/InvalidTemplateOperatorError/cdesc-InvalidTemplateOperatorError.ri new file mode 100644 index 0000000000000000000000000000000000000000..f69f1813a12a40f81de1a13788f1e1afbd0b06fb GIT binary patch literal 575 zcmaJM!H`1z#WCWJsJ zk|WFZ%X`n+igmYLa0kG=?_;)m8Ve;tNqi&Fz4P3?+2F^B2?vUQr79h}Cw?g|EMpKLAUBOHi z#aSF~IRDxEh=ebM_LX(zJefVAbfV#M#Zhy)QNsOJ3O8FVTspq)`!q*x(R)F9!U7u@ zPFGTiJmE@Km-sF7atAV@s&7oErj@>Y71&7q;>s17w)CANrCF7=(LQK!WhIpPNV8#@ zjnZP!pQwoPWLS5WcSuECL@=`JO36CZBN$sUUesPReY$T+zK2D0NuC@??Sh51*o|iU xT_HQ@<2b}Y!InEu=N*kt5AYoDq|rqz2kF+$!Il)89_GpEpBoKt+}6K8$`={}wb%dv literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/InvalidTemplateValueError/cdesc-InvalidTemplateValueError.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/InvalidTemplateValueError/cdesc-InvalidTemplateValueError.ri new file mode 100644 index 0000000000000000000000000000000000000000..a01b4ff0c188102778e789d7792171dd1e2296f8 GIT binary patch literal 557 zcmZ`%O-sZu5Z!~MWxqfL4=Pgn19p4yGQCt*7kW@+KfLr%rcJsVOq-CTt3Tg#KM+v~ zOc-X~%zH06^Ve{-c$6i;i_|rWnLuN*OYW!PUE1tWaJpi(5@^{Qik3ZTEj0o1G*83( z2TCEj!;{(#`-Ww6l!ZSB4f{w zeRsp{&)!$mxY4M#q$@jC3*?5;fL8%F0Y7L6>`_GEB(*HyCNQm1f-^cHjsf(OiVK#8 zf#AgyzjaMdz=3%Cm&}WjZX`(bo01uGN1RNql3L8DUzJ0;q{+S=yuG@-{0a3NMNq` literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/%5b%5d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/%5b%5d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..19bafd7a5db4a18bba734f8f4cd5533b0490ac25 GIT binary patch literal 1117 zcmZux!A{#i5am!AN}#>aN>!_NYAzr}!Rm3Ns!4%VmI|sM^kN}vZBOD=*1Ohvoshrp ztZfKsd&*`r`{unjZ}MXAjvd`x=#;UsT3?~fbrv0o-O%5S?mgyRPD1}=oMi^9iYF2o zn_^K)Zs~NzZJJ+j%a5sa=uIZ9SJsIXsb=q6$SZCZb;%gv*99uO$9kiZ8(T$(ntj-= z`Na*N8(!w#@MYwM{+Dr@Qd6uT<)y6+X0YV4rtirb6fY38aYvytd>Byw=|7O)C0C1| zLg9`c?su>!jsPzpy0u2Ac^_`qMWSUNCgMTW#XT%=-Gcq4;WwIuTT$#1y}i&sKW|yJ z{T&y_X#m&SBG{Z;SmmgIHzKH!qq-6{Z|jMTHx2y@J%gZ6eiq7-e?lt|6<7_0C`8(!`0oAoI0zu;OQFr6sbL4BnKlKt!N!P>k479@9TR*X zl#urzQ8n_12TmyE;4+*+Y4lQLnDv2^BxCp*hR;J@L7fVzf$xn^#Xwg7j z(JXo8TFq_VG8`U0qxN~!iic?IdeMx!SviK!*!5@(&YbOlK&lPJwbUwezLQywOB0jL zm`D`ecHF)-N?=8tl(tW5UA22kiEyshYN7N>H9kE~sRMZZG_3Bz>pp+9eW1dW=)lGU z!u!9eO>|mknkF64yJv|YEtN%{HK8Zt*#2lHB!)gnk(}|(vYy#)R|h6>wy|KO3t{7& z9+NdyJTtn8t=sEZ&tjtJLRQ5IO1%n#AleE2Hzy>&?`8#GT|!PB(CC!@7G6E=KV41I Qx9vJ#yPU~$$*U^(1JinC3jhEB literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/captures-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/captures-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c5cac22b1c6d981db6201c36e4522d0984b5f82d GIT binary patch literal 272 zcmYL@F;BxV5QRG+w<2n%iiHJ*1(w$HbxB2ulpzc#Oc|`R;}8oww(N@#|DIGuWxIFM zd*64n`he~G$t!^4_)}{deAjNxvdY&A15HsU2JE$|^4+oP=9Exc4bW&8EYf_{NNPAC z;p4S%U}Xten4~qz!~JEx#`rY_fSENpJ<5gg5Y?fq6x(qjg%+ApgrL_%=hej}i9v^?#kEhOh>^6mwvn{U?kZ0IeP?Vr zc1fWZX?Nz$n>Qc(CRp+Ji(6H4{-8_?%}oQ=X76N>M$>z6Wqk_{7-x6$H2U(js*JD} zibin06s>N+;pvD=7{bQiieI91EMZHWLBmw^U zr@yh^!NA6Vt{J-hG@37KX~U8PhDK;qf)N_HEY zuZ?PRN6pFAIxkh{NMBxvMs4F{6er_23$jrfO4u>cz3gQ!O>06KdVzfS<84%*Xzw^~`3?}l|` zL2cs2Ht>wCGebxB+0UHH;V6c#l;;3{f~Mak8Vu9DAqQI9qs>Sf=SyI6P7O$=`1LZj oIxP1Mjr!Sf{sU{1s>=fD#lu>A!{FKMB8@)&^8r!D^7SM91K2AGeE8k2}9ben^f>j(X*}i4D_n0DYc}gViG&F7u2B9#2rP?fA742hNXtO zbo|5EiQLCI!$wO(fQ%6DUQu(o91ZPAG^?#Cs|U!HB&r}-GP3t{X^62`Y~c9L;tyvc zK(3y+WG&@)cdSXEH!u=!G4EvYpWqFFf9z~9v>Oy$u*fBXr$hK@ZHT+l20C5)p KK->#3#`^+dAe-(0 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/keys-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/keys-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..58ed8443316f08140779334df4106d353a390c30 GIT binary patch literal 264 zcmYL@F;BxV5QRG+w-AY`VqrmM0S4;%x}>5+$`A$=rVQ5Eafnqrj_iw2|2-*1usxmL zz3;nNeZcyCA2h&jI97)G&^BwkEcxZZ91{cfT9^E3*S685gvuF!+W65S&8b4t{T>PL zf67}{6p)RRa#jbpJCB)Dvbm>ymrKQklepwuv8Z@{=a3>GqNtSC-eHclm^xxOPrQI%% z`|decn|IiqPeB13{dcYN5W03})|_rVI-LlR*M`%lW7kEU5=yH98tq1lc}_KEHJmWx z{n9>=s)Ayiq%|tQ?J`_r{G3LBnKC);^9G7?#F$gNf^FFwt2w>1M(*(+vd_Pa=P1d6 zG{DN>OcsO2&iIcc`WT$Z7atLNp@PrzauQP8@WmKwSDdaN9xtzDQE__xXF8uMb+eeg Mh3L?}SWJoi0J+FkQ~&?~ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/new-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..b7eb12e6f02f26338a435c5ecfba0157f8256477 GIT binary patch literal 582 zcmZXR&1>8+5XEx{&L$~2gQ-h029*`M6u>Ftee5HHQsfCrZ>BR6R!Q{)bNIzb-tz+-0){MC1 ze$W);wxG~-Hxvjlex4=sB_0oBtyN?3_11Mk?r|ItC1UK^gb5z!1G(VKLyK>o|M^ai z){cfQnH`pb@b22N1bHA3f7r!=t$%P6rXZ1m_xWYPgYWF9TT%UF2Q`B-K9C7Y+*)Xr z6SaPtM)`jbSDMV@S7mt5&W<8TQlx1_rXI>?gSfjb9$<88YxAPtdv-Mi)gNpfJ}o;2 z5kTlD$iWc)j1e~Ep^uXkG+I+c{Y{3i@|AT`$?zy&Da}O+TGbcyZy6VVO{T7n6qx0< zSE1^dT4mP0S~=TSA?~fRtE#ak$O?Q_v$mTo%gVhXefwToIN#x%3(GKw_(L?z&*nvX VvYW3w&6~6B(!NDDeXYs+>=#vFz7PNa literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/post_match-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/post_match-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6068a7008abb6132a1d81c9eec7b2f1c040e88a2 GIT binary patch literal 276 zcmYk0F;BxV5QRISv?3BL6$=Xr3oO+0bxB2ulpzdNm@-&r#~~JWF0wB|{Cg4=0o&>6 z-uu3b%^Pe_N74X?;j1#-Q`>Cqy3DReiYz^{?h{B}>M|3DwhbmmRL%g@#*YqpzN+Qt zh>Z9DD*L1;ARQ;=tR}cUBPt9Z(+Dv0CT|AbK$?#jI5sP|%scB$ncX?7cKAoy@ek-J zsAQkiAae4SWpA*x!+VrnATN25lGI5}1JBD*D&y!=2+^#{Z2j=KRP(ebv#Vd-IV$wc O+3b~qNB8V7M)3^>0$Q2? literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/pre_match-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/pre_match-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..300d305226beaf7d9259b9ece22223fcaa3aa70a GIT binary patch literal 475 zcmZXRO-sW-5QaTS8e6SUiWfaB5kxO-&byaXYan1nw4Q>5NwR4|_lw;P+JEn+EmrZi z4DUQM^X#$zj>oTaSztU9n+3JCEYoq*OM;=&G~-~4+QZ&soCMQZS!!wwV(%^apL>#`Xh20jmTM;1ijn44jzr% XZw!C5yHZ?S?DRcL&4E2IFedy4o8Xuf literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/string-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/string-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..448aed011fe6019023eba210fa4efaacd4b9b959 GIT binary patch literal 268 zcmYL@F>Avx5QQ@oCDhOymrG=7czAO$+4I11bxRVEQmgQJfvW#@5^xxMZq1_(G zyZ3!Jt4~-T4?zR$ho90=AKH3tmy&0Rq8&~Q*n1`U>%MKHNeLTg04n20hcu@WN%sdN ze7e?mtSBHGr^ZzKV?f-$R;*y z$0`tc@Rn3>u${e<>SFMU&O$15N{4~w<)j+p!nY8jUP!)temTG9St0q|pXz)n^!>%` MBSeqx&0$L77r3EUTmS$7 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/template-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/template-i.ri new file mode 100644 index 0000000..d59941e --- /dev/null +++ b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/template-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" template:ETI".Addressable::Template::MatchData#template;FI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"$@return [Addressable::Template];To:RDoc::Markup::Verbatim; [I"%The Template used for the match.;T: @format0: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Addressable::Template::MatchData;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/to_a-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/to_a-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f933571359a9d5162f90ed3448db757b24dc8b30 GIT binary patch literal 447 zcmZXQOH0E*6op+#(ibkIxY5NBH|nCzdb&xm1|n3Xv~Gfgo8+b$oMghxjivwINh*rC zo5y*4ob$nsPd6)-alWjNYot=;@l?2xHzbvS!=0xv@*b9XuF)7sC33#Ss*ynUvEcbISWd}heqY_!wF=Ebkn}~s7h0ul=O6*uz zp`=s?`}psch=z2&VKQ;uYC%$tJ7F7 L9ff?9V2u9-k|mI{ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/to_s-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/to_s-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a447681441bd1c8dc667f47e646ea205886209c6 GIT binary patch literal 421 zcmZXQK}*9x5QRO+CN)|pR4)pKcu^1So;Q~*)<6ywsjZhF%Ou$}!A&;oZV>;yn?w}x zHq6YM`QAHr_hi0Z%Z!j!^SR-slzB3*oH&>m$uuJ9F^YrxRh}!ZHKc+Qvg36tz}RX7 zCM(xq;AU73Q4|rc?NU)?l3b2wH=y3TmJs`+t9fHw;?WkA(TO9;)!&_GP;gMtmMEMg zC=Sl4;-*uLpS&1VHHSA8qTRpCuUw^Is@fSv*SnJYbx+1~f4_}=(Ecc2^m1}a3#sfJ zlM`B0g2#a`s&omz7MJGR;XieZtwa&o!M}wKPlQ)lwFLGJoSv?L4ely3lJ)U%m4rY literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/uri-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/uri-i.ri new file mode 100644 index 0000000..876e82e --- /dev/null +++ b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/uri-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"uri:ETI")Addressable::Template::MatchData#uri;FI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Addressable::URI];To:RDoc::Markup::Verbatim; [I"3The URI that the Template was matched against.;T: @format0: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Addressable::Template::MatchData;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/values-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/values-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2303ee9570a6b1d6aaaf53dd8b9e6a6963b3af6c GIT binary patch literal 583 zcmZXRL2KJU5QTdvvKlA3#Prf02IZ1MaCGge2bm-W9UMY%dJ#p8q*1hVwJUZsg-I+>=mELcNTT|x?Im@E?E2@E9AcFgK7G1CE+LCivDiUH# zU9XV+YlB?1cgT2oTu*}aTFm>QRI)PS%Y@#b{XO(Tc%7jm&7qj5Jz948%!se=cOKE= zi^aYTl23V%MT^uD4^~6IvKIHhf+X1f2mVR6M3&vm--KE8W7`ra=@?7{lQG~H8Fpj| zD(pRwYAE-9O7QlZ<;lp-qT2_!F98=cjBr>WkCVlRM;CoTQCZlttb_d4vB7xZz{| zOIsdJ;?#7Kiho0C!{}1oDs(RX1B^er`2YX_ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/values_at-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/values_at-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b1613bf0339c1189a55cfd84a61d82fc760c83ae GIT binary patch literal 671 zcmaiy&2Q5{5XE~yZfQfgL|j1CDqH}iiO=hc1Fa=X1fe$cVpZ1I9>=ThhqXH{&416@ zZW}%h+*YI6_j@yMUL5`4)2j&KcXN>_(|IpQj~_j9RX{wcU{Z5r*#T79r2U61xqfQ82;|h zp6_5`YoTp|=w%k9v&9usXSHLhlO$S+tc2EAuwo;X0WqUXTm(_D`A6=v1bz2aXgn~{ z@uTE<4+q7vYqCOb=j?i?3M1z%5f8dkx9pS96+WOF75^II25kW()ZyrFp6W`J=$NS) zHP7xGBf|=0c5siCX9pWTiECpOP`EcUjmH+2t*nLJ?ZAvCPwF>A7OXVZC(s(t(%W8o zEACM<@3Utw2KDIGZ?fmHLuCIAE*p6KIIe}nbjGA8matEINsnPKY%vTF#zqOs8-(77 z%WG>?PW@rzrp`;F$;a#R0;TyGhGBM)&R&0bTIa`JB0lpMb^3fdzLb=2#uNC~??!%+ H;9U3%)}q(_ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/variables-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/MatchData/variables-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d401b806a5868f368e13beda62f5b5b5b3ec639f GIT binary patch literal 617 zcmZWnJ#X7E5bY31iqm+B(WM;-b!iq`Ybl_RQP%(m2Swm?5dz^PogyNXD3GTZ{`Vy# zHy`LmJl=cv?%th6cYJZX(G}Z4yT^qF4W1R1? z8x)Xx?SQIw0|Z}R8ELTH@{3_Cm8>-XJT=&Xc^n7MUAM8ro+5sc4PeOTq2^!S*Zc+p z4+e%dNYC>?#EZ-zjizV$+88+A2WhbXPxud-5=eHT<3u9>pT(6^z#F;&HO!DQ~RY-HN3*z&~bwY!=)n(m_0&U|wpk6PNtk3;f4*t$BBBH) z8D`$go0l9#FYIi6t82y{G`1j@609vwMU=-^&%8Af9Dg(%!D(Dn8Xa%$5H%7;?pAqx zvuGOR)0f9{Jo04YKsA5^T}qxcyZBae5BR<_jConRmMa&rab^IWEr?FT zD2@EiE`Rqv0m3VSc_Uppj~8nYmN!&vDJUw`9;9ff8z!Q97>No?cYU9tKn*y@QO${0 z!$#RwNS?=3is~AE#=Jg|%(3bllT5e5m2VsxpKNkVIGg_&hn0_h>DPn&90K7_Vtj>3~I+~?|Gk242r#fk1omMsZiEiSn~rk yopgnC+Q*rXK|x*)o-R8XpN_GO=M!2LkqDB(&0r8kvg15H|Mx}x9jp59NBIH-(zVP0 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/cdesc-Template.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/cdesc-Template.ri new file mode 100644 index 0000000000000000000000000000000000000000..42653fb34e7840f20d9b0770bd9d3da5cf374066 GIT binary patch literal 1734 zcma)-@oU;Z6vzExM60$A9WAV*3)vX!FEuc>!G*Fon?gowOVl#R58+HM_1c)rE@#{A zuirb9)VS3-5G3!t`@HYH%YE~#Hb%S73G)#eFh0XkKf-D1c4*Dkwnt=^L|707Db}g2 zz3c@6Cuxc&5kcrNX(*6uTug3=FBC%=F|?ln&oRH9CkO$3J|nTHp@x}YE>c%vMzvPD!9bO3JXc z56)>{{q*s(uD+iNk)Uo@Fczgpl!)+%@$2qX%%Uz2eOYsOBp0E&8PbT@ni|nb7cckQ zEt(wh$)Zp<*^CNrN^n5q>(mQ5n|VTx#$%!9vsi%8)SHlq-RnkOHyXODxOH1=CRhl< z<4mLCENG2nK8dIggWS~E-5#S(HnTp9Q-NdQwrB-T%dv)*b7h?X5IAq2JS>FDRl1&^ zL&d0@ZBS^o&8q+R>!6Q~?W{>_JSYQf?cJI-t94H{GG8yb&8wa>=$%`c_BU&wrK0~L z4lk|#Mq*L4k=TazcJJ$%<(=8XQN}%7uXMF^BfVvPzl6~a?TbN%UN_m*x{ciCnbkY7 zoZ-LcP%7F?{B~gvHWEuk>xgc}t;#!I_oe56z>y1g-e|%-foLrz_cCVgxmC22a3;WC zNFW!XX2R(m7?XT}H=i!{AaE)>z`Z07g5!mS z6%pVjnW^QGty}VQAv9Z3pJCyHQx%AgbT^74?@#vb9p-f54FL)9JQ5O;Gk1#IW6ao* z`!ZT?Q|fwt!)WZ?;b=}CD{QS3FWj2`B3`a3$Guo47HgJ`4j2yzCjqe5irI%9q{J)C z&Rcp_j^BkD#c2r5Js&4x&gIba+`%$e3}UsW;wt0f;{fI*VB!c3VZvbNZjDw-c9i+0 V*@pd>u9)oQ@0CAS=PZ~<VHAh>iA|CP6$m!vyxFd`_Eh6W7RumeIflMG{3#=Of7RNh< zN5YT|nsp|4uGrl&r)vO&;*wkGZ>cJ*8H1{#(cnu>V6m_*L=zh<bT2@zUbw`L^7;p}VPFvH*!SBH z)(=W9FmkBi*%W>{Pwk=dL}xpp8>pJwq(UgTT$-fRs!nV>Pol~sSJG}vnW& joya-6IYMq*L~tHP&hR+p_7dh7`(0j@u0cEqFvk4`e%OVG literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/expand-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/expand-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..18b9cd986b2c172bd69a24706e3c821700988c90 GIT binary patch literal 2609 zcmc&$TW=dh6z&6ZFKJpHN`*v0CmW!NY<4Ypfpr}@p^3VJgsLQcaf3CxJ8KVF&nz>u zbwX8sJ7+HIIF17d3E>BOXJ^iLzVF;TAKW>KAH8}mvN+!57l%|&L_U1PZYRMSJ+BDQ zTXAduAPF{h^ITG;NLtc3KBm*EB${seGriWqLA+MgX~{AXf8y{Ci9D;TI7aY#O1Zuh zuMH|9wHiJY@sq1(UJ^;hl2nsc@9wab1f6~BTmgZTR|#nE4;a@1-xYOPnvJm4YaL$$ z+ban_`;l>aOZ4s;KveU>xF%B=z94FH3R6;5jE~`XLg&wVLNsJTqRdM0Tmib$xL*;i zspKITXG!o?gS7dUlq|<6bYN3U!c`&U^b{&7G7OZEj@wc&UQ?M8&8D}V&Tn=(h)OfT zNqK1rBK?(S8kt={N9d2`KGCrotoJxhBgs_L-Hy~lLc&MY5P^PpLczT+gQP4Ai z(Z#e-46us9m~mV==Sz4 ztVrt`8CC^=kVgWj2gyNtt9+8o|bE8}4*dVUm zFWK+7BltWZh+&E!%}hCZs6k5cB?VJ3q`*=FMR{)8+lY0#d@s+5gA0xwAcF_KlW_3F z17A18D+3Q_&8e+AH}KH^;#j(dvOb{a1V<#bGoW|hboFfUi(J#X{GdOL39&MY7F_zHpL-1Qo z|E)bdrZWW_%7eFnYaIETdD}ty4K|A;hI**qvSMj-f zof=%pPSaN*r?V}O&;bZ0T32xt`CNpVm_~{cnN6a1HYo3-CM*xPLzmgcJOX&uG-F3+q#-_ZPN3f#~}Qt zG4R5cg+BjVplqLHf7>S*W%%EsPGRn>agWJwCDt0syF>B|-^V|#Wz#rC)} zV+bPr_nx_U*##2Rr}AWuXU=yym-R>Y-$ZK%zlt=9cB}IjOy?pSt?{LptgyFQ(o}b% z&fb1Z$ZnQNrW8#I7Db1wtP85yMti8=+24n169Dxxo3#urqcG<6hV`le)+z8@_Q zYbv!GeJrB&#WSy{q*F=jywiU$>cr&Po`Y9Fp`>-qt0_#RC_(28-WHz1xBv^x2NSL~kXKlCu$h7c`bv>*@jcVR<|vC{Gg8p&P0YqI`iGNGE6 zOOEkZhn|@h;BB#t1H|eaMk~XKkR{cS+;&2I1|fZl*u1i2-HX!n#*`^M0g2Fg00!g6{nBE42Q z(BEgmZ|DwSX5@QQN~RlGwS}S9b!VQdO)4r)dFAFsvT0LLi7i^2c}D$^(i#&mm`c&q zfSTJ>7SUX@22gDZq}UoaO!1xqvXRM;Ahj@6))UN_)yILJ2GPV6m& zSBLB^#Z}7Y2!0)t_0+J2J@@Way9>Mr-vFT9pja^p{BUlX8R7f|-!ML%|; zU5_}?1UuKIBQ}6c$^W4Er#losF1XU~!gtq|uPv0jb@+!nb&g14l&9qA(ku$xdC|k+ zgcmF(Q1B$ASKnsgY}?4hoQ--zQF1-b8O?B$tFc*UV{JC~SWL#|rvbmr)Hq>?^H(VRDRAFmMV{jyc@X(T$-9?=uqcAj9hn`=b9McV6-0;T(HO`f~RBno^6cV)kZp9r=nhMUp9rwxmf?Ce(-Ld2uIlyBC-1r@@i^lEYnPdlP2I?Ve9cS0HW$ H7~_2b(6XGs literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/join_values-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/join_values-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7f3ab62bb22852f4edea78bf1fea9d65ec5a1178 GIT binary patch literal 817 zcmZXSL2uJQ5QTd{ZYe3^P$3~e8o5$Qgq1`+t`9g+B3aOaAaJoFYaCCKCF@;lcay09 zo?SauTR2%BkLP{w%{)2z#m;|Rs|8~dd3Qs0t;+12AE)7qKZ?tIhhj@6V8Q2U8eUGy zQj;-Q2x4qTRV~oc#lyxpm`+)*)_mu_DE7J?eS>GV+lr(;Vb78pwKZ8!u{V!< zzN5yK#(EvZPcz3cnc;>EAQ-Zsme3MKfU*RyY{0Im0;^UIo-`C_s01Z_8G<;NrQvf` zlSZrb(7*qu_)(zTeC3jkRD9}HgEYMMd{{yD(`qhP5!`Yyhi(phljK>vL{~Gg)XH(V zk|S+}{;~g?bb*#v$F0Uy|3h>cy^k)UI2uL6K?F*J!&*#@XDl`mdy}X3&DR}K(osLob E0OMRykN^Mx literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/match-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/match-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..229b4ee06fe875ed28499c0fb619b521bb24ba70 GIT binary patch literal 2813 zcmd5;U2hvj6zv0Y+N2Spq>+FWU2Ujv8sqf?53r6~hmZ(Mw5m$l7ZW+NyJPQ=^~^Fe zn>330-?{VUk9-t_c%V<|_|84&o_p@y`Q-lFWaG`xB1@8ee)*E>Lgd2@wlauTr$lE( zBWWBS4Ixl4T6lg{aFM zkU=GQ4u(8KjinWOPwVHN+g^-+gOEPO!2D#%x*w*-8WXB80#c!iHW-W>_ovog;6Qz< zz9wfB^o79oVJ|3lP$h6W{7p-2@d+LHQdvZE&DKw}>5pcay?;(5GpoSy%juZZr8auh6qth3sQv6kG;7e&-Le!!0Y}q~ z$Hv2mG{r>Brq^gvYy!d2@RUA7+SoeNG^coXePN!S^qmwi{Dr8Z1+Q3nP!gq17KRAd z+Cd;=qP%-aRhdGK5#RzD`2oh>FD{+d-2XoqYjak*`)q6tV)jzba{jFuMqHitFbwQ1 zgxCA@J;6mv7YKegh_*7r8V=oWufrhJil9|8Y)J#1Ur z6IG|p`1jqo1rbC$fTYbm==C7_v!?Pg@>e&nU-jo}0F>wcKVg?_Ezq$=TQY&g&O$0{ zi6zuAlS&8F$IGGNcnS2uP5f!&+K5`X109+n9Ek zJmqWqe7pA?hQ5O*{&2&^`q2)dPhBYC=x^&gbdga2T>Hc2(ApOtmG(A4Nu0)690kVz zT(9_cy{@c7KEzkp7+hodeGxh5Bz7Z_|qx;RUR67X80d>k55s#CkSY z>(PS2LUZo0)4$T@%egkgC^ZV9K6dTmf=*WZV^&gpLY6Fz$^01^&sL*M?Hj4n7gMH3 z1tmFdV>L3nccjf{W+cWV^Bu!yq#C8P6c?RNXLxTAebKZtGkY)fa3}AWWc?vNTGzvD T;>l6A>E4{L%sb3|89ILf_NQkn literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/new-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..fd45eb818ee1f75ff5e5074e527d3d04882ad9da GIT binary patch literal 521 zcmZvZ&riZI6vsK3i4ZxV7fo#DMK7?Mu@EyvNS25(WSkbVblU?eUAwezA^O+b@gr#T z*5tkS>G#J;eMZ~U7nM>vke?I4mCB+vKMmZvgpEU;Q5d*4gDlfv3`+!18bV$OhW1r$ z^qg@>n?;!jo+^5^Lrs`omj$JkTjn6KPMdzgG@7WP==JZNcc$4=vts4+&LSspABP$& z-4I4BpY#!*{{6n+wG*O}4@j|NWrTmo&w|PIE0<7Hy~dvYQ0ZVfiEdHF2KAg23=y;> z;R?uX8jyp%!(hwyTSvsm*MOzHi2l_z-;%iG$eG|@kR6FX#L|Yp-~s}d2%dD=G2brk zb@fQ7vsP^ VKiH}YOD}g7yeXYCF%--g?;H4gsvQ6T literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/normalize_keys-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/normalize_keys-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f40a56a63a9d52f1a5073196284887d82b9860da GIT binary patch literal 548 zcmZXR%}>HW5XCu|f`D8g#zYTmO^jTmClAY|_<=SNV+?v}Of#iZx}n`|b{7f$^=?ar zD7Vedq__sT>#$(#fCHpc%K~FaV6OfB#PN`8_X2^Aew%i<~R(?y+v%fp9AYm>c zPpsjgZ+Z6RBXX36rU;M(R6q^v1$ty%L-ZS}uG6c=C`sV)g(caZ8W*BWxr)@Vb z0@n_0x-m=9vq{Rr0qpV~=qm1O85Ww-kRU|HfeKW0(}g;Y{e>p(pjCI6-9S5_C%wyc?7xZ1 zlF=B*Ta+@vu5ZEO>HXoAw_eM6&+5kgCHZ`^xB_m5UP|XTbg1o#d=&P;)}%9%FaDnS z3=A8FzV=oRQ^yk}(4Y|@3|c{z*g=`409}foq_h#X#!gt;xDd!92ZN;`Jst~hS{!T)0>n#EW{)eanL;@1 z05;@$i;-^sk1a(}z^rGpPj?=!PS`c_$It^Lhrv-7Cos)>H> zE#eRDfori88<4qoCaN8wHr;zrEqkZp(b~7F@m)-xgR05;Pbp>FZ_BX1&zUDXSMp%?*%nex%-tnYX&32%+D^j58l1W;GC@Gl2{)rb+l= zvRF9u9&(LR&exxg9>I)*=~V95PW@&kD-V0YOK>+$EhVcr6&l)+dodG`Pxq{R{qLV2 z;9%vTE`#yYG)ThpFKEy)n-^4~I3YTl;R^rMCnJ9H3`lflyZ|v|;7OO^I2Z@>2NLHR z%*{7taLbN&TNy6lV`~U1k^Us7%<6hz5OWs2nk5gZMa!Lprvvb)0xC)dI$LmG)^*U0 zqrYRaqVd>Si=VF@aL^aALu#B6X`k=9_x@jnztH7Cs@m?``8p8}SB(ZIxRQ2H${KN7 zs-hGX+=(1pt%YFCuB690lKb(}I!+MD-FT@qCZW(OAHin%qan(%%Uf$QifyGRD-jml zn9r8ZRvEQ-lG$ZeSVO#OpXI3SZ4^c6RuaB>yI#!uO--jp>31z*{EE-**>GVznHDem O+xXsE)1NeWAKe4d`R+Ra literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/partial_expand-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/partial_expand-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a39f37734c7ebb93ee417b33a8d22be8fa0b26d3 GIT binary patch literal 2139 zcmbtWU2oeq6z#*{c5Sl_Xt9@Vz=Z;I3E;_20}Pm)bWXMe6}DtUm-NL53`)9=xKN}( z(si;R|9zJf<L+B@hRA16=hX(o8Cl5ZOP6Q-}Gb&^oA zX@$~0N}deeIWziFCEqUY`IBjOsaaii2A_{QY4qcfCt-lW`I{7Ms0&L%E>yV8*WRsyhWWc%d3Zt;@txY zsChEowjb1el}3k7M>u3kH5CN}6;1?l zZ=BPzXYH$&_Fj)3Kb!&4S&0^&;aEZq4%Eht8Eg{IPSR6Td!h~rc z2TS|-#EbMbLA4K>yM_R6zlRb#544T+)=4?iTIoh<6RcCb z&e3N9W?TsO<~1Xf0v6a%b>6_;`>^!d8oWQ&`r%SA-%i-?SWwkyWv=-g<-e?^2J!sb zoL}u+ne-U;AS!Hntu3mqG~F#rGn literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/pattern-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/pattern-i.ri new file mode 100644 index 0000000..7f529be --- /dev/null +++ b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/pattern-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" pattern:ETI""Addressable::Template#pattern;FI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"4@return [String] The Template object's pattern.;T: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Addressable::Template;FcRDoc::NormalClass0 \ No newline at end of file diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/transform_capture-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/transform_capture-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..263607f4b719a57091f75e80ba679a7a9fdc1a52 GIT binary patch literal 1648 zcmah~T~8D-6!pO@h=4v2UL>(u5~InoY+`(wMYEs~M*)p4yllv(Gjo@%blOSV;lp3= zy=`Zg4~;K`PH)dS_uP+tym*qV{rIHwB-vFrN8qNq7_Etgw7u>OS9YRJInH_IY6GpL zwSSPdJG(_;z*?S3NRlCxmE;aKABOi^2M5V=WyB@k>*PhCIpXG`u95^f>k^b(Or8!Z zZk!#h>SW_?%y(}1x#88c)qgTVO<#tMCd)W0c~wEdF1f6MSOINT#i3B}NcWc_eV>H#l8rudJ3aIKLY=cAVv-j6 zA1Mr=AvvG~@0yK#8_naN&S2zOb0666nR5yz<4%+dn0G5}za$E{uE=(w)h!m3)*2?u z1F92uy{HwRY&CS7=#MC{0v$H5(HX0Z&Jj%;&);8;OmBA;)0IOKF6S{!XTKnKnB`4y zwW_3mqU+iFD-G@Qw7o}4W3-*>S{CSst+XmgGzj$H_#*5$_n}d?vyBI)O>`=yyIDJh z%aR)I94tj;+D*G`5C8rHi6a}Om9~%n3PnwBS(NAa1u%D|nXfH4Fg9WIOz{!|`8_<} zaQ>$2YyU8n($7)DU;w8_c}!>Oh#B-9VLJ4D!lext{d;j@;*$(buA74qG<{51>UU9e zV!Ge%VllJ`%$2avWms3bOqGAoOzkPn&b~3)giPT&2VeaN`1MLiNhLQNQE-MD0W@;R zE&|-#hX-XNuOryetRcJ~sEy6S{T#=vLav-foFs>NiGHUO{QAGzlCm1*c5Yec6H(ex zG8LE{HxC1q>jIer-XX7@#vu|pm-42|PL!Z)rf9UJ_>DI>dW|87K{JQ1sT~m&Pr&A# z@{Uiim6!!p_`QJ1hP>hunq|&Hv-mAEcy@b$W8aLLg+Zf*O8_~Lb-oQqeX=x|2nlJM zNs(>y`GVe_Z8?+qz}`TY!i}fENtYc@j4sEHx@oK@<6J9;&e(AVQeX9Yz0sqz{pxkx nZk=Xlb>^$#y%O>bArH3jw_&AeEc|kiuZL}Z><#=VxwXAN&}Ax8 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/Template/transform_partial_capture-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/Template/transform_partial_capture-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..7e015338a5741bd6aff8a167e9ed364beacf0860 GIT binary patch literal 1665 zcmah~O>fgc5bXhluYx#K94JDgZ~-Z#LBPc+C@oN7(E_4rFHsdu>~Xzxy=(2RTf(nr zc5Nq3OT{ILy|ZuLn|U+2b>}GB`1wgEQM9Ax2jp^{PBz5txckf*R5sJ5n3iaqKsimY zbd{k_)cL#@ci--$sUd4|CMk->RFo1OJ-_+du(P)pt(QiebDWMg>$C@G&Z;tsm_t>N za(ANpBcISt9_i@mYRnHbcxtfBJHxw^PTc*vuXSm`vvU>fBoMSRG zbfUOjGu=ES2Ref@nloSBFk{@#I9eb1Dx(`L6FqGc9Xi7VPg+%h>2SRPeKyX?Bl#`} zt*+n>A6x=_)dD`}I*61T(1T^GPM|b8VH9mvGrZYRpi9T#D3>vyXTKIMp2IT&ccCG4nj9G$1$GJxs*_*A3&sj3 zeeiOxODV!wwHXZY5UCL6Ox0l4{0>--zn-DA^}+B;oXCR6kkk9g*X|sRs2y#+%SGC2 zXvIuAFg(`-u2#`lNP_8GUsdt?5+yC_zm|4YidzVTVgedL2 zn37Dwiw8(0I_1nY-ab}N^HhoirJVQSNC|%o%Fn74fB1w)t}O^-_#x)o-j0mQPfU8@ zymy$fmB5lpd7dv3;W1cI4z*eOp2X^Wv!?rI76Jz&T?jYL2|X`6&5SOl&bw)&}~bzkTm;@XpTXk1A(uD!*rBD^(=t{3!NEU#K}|g3^LYY=t!*^PZyEznvC^CS$r8 zV+*PqftIfR$|qhFv6H6F1kV+_*t*P6uiAz&XW7;y?SP$x4QgwWfnt}xHE*bKsj;cN z$#LS4qB+@CO9KcsHVv0cP$l%n2CM>G5!bLIb|cY}0n<>DusilK zeC+;eV9i|wt?f@ZFHIno1-@fAe$8M5V z6UV%~->2W3_&2|K`mP(!7izyk*Xg#r5$8qn_AiitTB413^sp?FkBhb?v^LB*U*pb5 zaCmoG%cA9yUz)y_qS5^Qz`6q3_J(sW(eF^Xm|x}w$k{U1{KM;=UqJ9oV7e%qm9rvw zctY2cvJ4bk5W$}54LjAz_EK^RV<^Nna(X?W0h5rn8GsROE}w>ChA_4^jTG*NI2|DelzMCp%d>DDjJY zBP14yZ>PS8(_`OHfH~E{5>Ioz6RzqITA`k8wIRK$T)2x$Z>mQ7D9YKYMyX%YG%cgj z-_vZ1dwWQf#j&@2mR;qy*>zeZ=byiXd4B7U?0UK@KUp^KhWq%bX$SI~1Z&fO(g5P` literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/%2b-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/%2b-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..851536373ed46508f0cc08fd6cb6cb104b5bfdaf GIT binary patch literal 234 zcmYMuF{{Eb7=>X6iN&s>gIip@2%7nGsi=hv-a&Ng5Rx|4VA`)FDRTe)O>yuCoaemb z)Y44@78sL8As}0$cJcqRFl{F>8@&jC? zd-WYa)cQuZA%QgOqzk?n!8EIl)toM^Q9JnscfB)Pry_U*mSJOpcxqXh_TfeCun}Rn u6H~YCa#9Y{A@iN6u+u*P?P0K8ufFoXuvMKmGHcPhj9+;MfG~``IK7 z(;d3bD9bKOUEwQdI=o!n(xwF| zexhZCc8y2UgtaDArG+~5`%2xCIAOI~Fi;f(DfOLYr`O}U5Dp-eb)&M+&d>%sid%Zh zf6Tp>pl;s_g=cy_^#+49T=*!UW!cBx!wu_Pp(Vi1G)tUS+)Zb}}?;xqQ#b~tl9HUJ#;gfwxX`;Ckc96** z#FS|ZF5=U;7828NE=93|)5WaF<5jR5QcLo-tBH6mrzR6gK%Vycf}m}%RldY7FOI^vFoDs z(}Mct8}Pj~j-A%nz`3_QoUVo=lP&WdFzU>(`Utru#^ww-iL59Exn2>6Xb ztA&z3!LbT`7m{>>7Ae)BG`B;&8a2U5hh`aa{}8@a!rWa-1ADlh1g6WMfSj3Z@5-xs%im_9Xm(v_`6UHb4gN^Hv-ji>IetU%#?k|f1m9?xD;{&h&FFS0zI(mLoPtDlW8 L;^VNb!AbH901nXP literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/CharacterClasses/cdesc-CharacterClasses.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/CharacterClasses/cdesc-CharacterClasses.ri new file mode 100644 index 0000000000000000000000000000000000000000..de32c4653a3f3fdadad48bc4cf4a67aa1aa467f2 GIT binary patch literal 1781 zcmb7FL2sKd6wYBH8EG0t)i!C}0dd)Bfvr-tnXZB*q_Naw83~gn4#**qhlI>O!=X+ZT=Z;2QRIA*;Fr72D& zAlU<`zPA<&hSL_kZ4F_bJNaa@P$Wsk-jkr*>2q)g#UtOUFCl%U8@NfR89kl=+vVns5f8C1a{cIDcSByL)YDm0mx=ZA`I2@ zh|D$gP`S2dq|4?xMmOn-aDR!>g2Z>JA2Pb~dDb7FhJGM27geYJ97lAc8?tURb+6`i zTyRztEow_Sin-S&HK@wg?PO>PV$thvd9MN3<8^)8&zd2d9id`&%zE&|1?#SHvK8yY z8#sH0*dG6+nECdBx_x7h{l0w*N7I7;qDnExLFFP-_uKPDj)O`?T8=%nou78UsN-Xm zIu1ih1={ZT5D(Q#tvU`W6_F>sq2)Z|s`vO(>gKdJv`2QqtyO8yLqI9{spZaw-yJyn zRq%hR!haM~D)Dk+&4va0hbrtlcqy^`!?m4l-j)94J-(E>HE^t(kv-o2yp=x6!;t?8 z2xqEijw|P`Dw;C$gad4Lj_)}DQ^7}Q>@`U3z{PT_6r{>y_vLt%L_%|G!DdIytH(E&U1;$7 JaJ=P%>@UD)?~?!k literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/InvalidURIError/cdesc-InvalidURIError.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/InvalidURIError/cdesc-InvalidURIError.ri new file mode 100644 index 0000000000000000000000000000000000000000..baeb79f1847e2423f43cdc042155a355c0f497f1 GIT binary patch literal 523 zcmZWmJ!``-5Y13zlP~D!k`Bg0$HY^I^OBM#prNHC&E&zHEhQF}EhEWoe|}{rp)^Hs z;&|`gy}P^cw{W+9Ryn|{(k04;L}QX`;nVPjR-Y&Z+pg(SYo!U0<%)(6PmF193}%u8 zI1u2R7!$|4+E}a@YIZ1&$-9Edq16lOkERB2eVdY3)`!8oMr}<(RP6b&?|!)d%Y8$Q zdyRELT9}59YZQjFK=Fs&;9vD(gI(G~-fzMR7lh2T{`No|kwu z?C0$cTcyNLJQ&nXCPnUW55~1tmgknUE*;ide4^!TLc@`$j9XdGPo?p&1>#W`$1e5~ ovOVo^(c1X702`+#RF(Lm7ah0PJDMW%OB&vu-^*SAg==M6@efiH1TB5*T$pdj9aFH+PEOra z$c$>6bljA2@T~!7(TE;v9+i>}WmMUT?TU=)a04`9`C5gk6j`XNV}v3NW07l9u?i#L iVrScS(D1G1?OkPc`{sHrQ=fTwalbD9wOY;hW!PWVO{8@I literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/authority%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/authority%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..64e717fdc1da62f4a65a52020b6ac827a7c50d21 GIT binary patch literal 451 zcmZvY%}c{D7>9R|Shs^9!^=E`?xG-D&nZIZN3q~U_Hil_(l%Yg(!3=}8T;=|ov1^P zZ}RdyzxQ|It;ull2st4$wV!iaL6Hu{Y2u%=)(u+N{T(9cDNcMmD+!?ZQ22juE_=Z$H$(X6RZc$T8XpDwvI z*j5~WTW}6_1ImGL3EKS$gI$aX3eoBh?_M&seG!WHAnboJpF2CNak{ixsLd@NTcF13 zcdYo1{&-f->R$dcf67QdDuv{UKawJwvY%R}trioVb%96_K`kt;I4hjX&{9K9ZC4(J vlIEbSJH*h8OV|ZLkoFRPczu-PrsG5xu6oa%>4rGJJe2kdx@Pi0GGl@d$~=^$ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/authority-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/authority-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..bc18f4232cab52f42d0cc25ce10ae8a66d497039 GIT binary patch literal 468 zcmZ{hK}*9x5QTe?G`8Ty;-!L1yeO75=dFj-Y9L@mYI_P2Hp!-0y4eY{8%qDZ8w(Z@ zkHgG-^WK{?cSA?3XUHj?tHY9;3W{VT`muMxT3etn2ZuT@QS9B!ivqdUER&ql%__b< zP0XAqqQj=mq{xAekH96vUE5G<>21xGap^E@7#f|pK(Bw#yfb85WKHGF&J%n6VO??Z z!zVe^4JgYXB_J`C(8LPxi8FK7vG=%uIunX(+u@|u94DkIHf>S( zn004q5JD|XT5(obpiWDKIyGIkDU@jr%2>BL&A5bp5Clmt_WF1C-D-GgpW#~jwuthp OV~%ftHIoZzT?b!}GMI`0 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/basename-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/basename-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e9e5a90b2a786ccb895c46eee333b6a086414308 GIT binary patch literal 418 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 YVe{9)knquoo>vR|r&%ieoD-$|zkT@o!2kdN literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/default_port-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/default_port-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..83873ac87610559eaa4ab5653a99fdd1cf9b46c8 GIT binary patch literal 550 zcmZvZy-&k15XC#75ZVc;Vkv_a2FgI2*%?Urh-5(#s@f?+k&|2+tBxJnj!OS~oTL&e zFrM!2z4y~Qb2oUrdX^c+3vpP2DP`A zA~z>TffGe|R5vMSnZ%P`c1hK)sWG-5O$EZZcof!D86CS4U!UH5P(`CwxG=P$(ZPFY_3_G<`3H=r(*ZU1Po*_Z227G zO~XDJiit3=1@(!36L(^G7#55J@g|(5bNW-lyishX($*0Bp{$rmN}xFtTb&e2R*7k= vN@S5_(mDvElN7kz`@SC!h<84{YhS~$?bfx)?GR;GeJAfyRg^z*s5gg5QcLoik-BlrX`Rb1{FdJ!4dSfzSwDF5Y#0Erx#PiNE%sNuXfCS*!929 zu9XtnoR*!PcjldE=hfgroZWxpN{Ff6&&jo1FVEz0p1!N8AyaHo$r_zxorvUimZz7~ zx;A7jmWqUUxX(YnNE|1#nK<3}Qpt+NMPGi7X6-jZgkHWQ?FQm>vO(kQa>(Mtzd3hk zaAk1QCgb69n5XkaD=l;fcYsRq&cdEOIED__1eUgBP(jtAUXhJ)gkTM_( zD@ex4B2V*OE2}oBLVt9m_ON5GYN*g#g6D~WjA3K1p!5!;hKluXud4{-Z>ccVlVSw0 zXz9>(CzXPdz|d1IssSxnW*tu#(gFY(l%?Wo4Q&Ya&fba|H_TvBO|0Gj}-|UWi-Ir;g;D8(8O&}O2JJ1W4hD`_2 zFs$S@m`fzXj`T!(HLx z@)X<@fv5{8Y*AA9)GW)EM|t|@)8&E7=U8BJ9(HaJnup7*df)HKk7z)BRcLMY2xcGW A{{R30 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/display_uri-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/display_uri-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b42c0fd7c7943f334b5cfbb5adb71791bcacfcd3 GIT binary patch literal 651 zcmZ`%-)q!B5blGd*Y?GS>PvlCBZxvt0z%cjT5?_+h+2`;J_QML$>g%!W;g6ki1**S zn;!TJALe1;oA3K(zIiaaAzREefAS~h3mDiK z=-Xg^R2=2uhowOvv<#TjVs;SZm06<=+Y2+&Y_Mo-#PWt&>_CyI7!X0Vb%O?3Fb}@v z;YTU9D0kXN zyRaqdc^r@97zv~%(q-l z<@W0)bCLJ{&zas!P}@&J;ennX`%?vZc%2%g!C5W-j_5mE{Qr9WV0vxQPD1=RZG^-; zJd_1g_W_Yvdow&qbtkB75o)0}wrq^<$|;soH)W+2xsYwSMybanNs5C!Jbdxe akEV~@2hCiNuF0y$_tAg$tIDMWYm=X#PSdsk literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/dup-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/dup-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5c39326c9695a62fb03f82a35a7b4c7c1e790eb9 GIT binary patch literal 379 zcmZXQ&r8EF7>0L{u5LFOg3Lpy7rm@Kf4y{02L&fGwo{RkwCNg`<}3Mu_}`m2LDX}; z_j&TZXW<@Z+Xt)xmhxl6OovT5|X-j`1a06^9#3J=wyDV Q`tnr$8C6fjN)WBnPZ|SuiU0rr literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/empty%3f-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/empty%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2fe9721d907e1e59035df3699d1bfde4abf11b1b GIT binary patch literal 505 zcmZXR&r8EF6vuav?w7~uWjloGL1An?r$alPg@O|qo0lRbZC}^0G$~2S*ne-@PDH)E z@bW(I`~AL)-VTp8E0JKl(JPk#S-Cz9+XDRay1hgM+ER-i!^ zl!HPvLpld!)*-48;iy@Pl$Mn5XO?Si|KXk(;fGf<-4X8KjJ)+E=t^=FZe<0}j3_ll zK4Ge@KU>fr?H?dxqG{1>W%-*1q0k}`DLiNcTFjfWR@vy9o_kqM{%#6mKpv@rMlQbe zG9e419X#+d${?`EjK*{FlkU8dbSC3k6LvgNP#xt!Qe#*}nG{8&>l;KOixR=L30Fli jFmZGoC+q}v_wK$P^{&j(dL}sY@RRE{^0#_5Yy3N3xyzyh literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/encode-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/encode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..21a41e646a4b4cbb791427a4e13e71954256505f GIT binary patch literal 964 zcmZ`&U2D`p6zzkgX}7g6r3kfpNueq%y8$1BNtLXv3qdQTZhZ+$m?V>C>?9LrCd&SM z=Od--s*f{s=bUrzIroWwiwX2~K8ZDTtIf zX9S_!n*^cZJ@V!YH0t`C(SoC6hjoR;ecvIZf%}HE%15KP!$Qe)pQGo0)?8zO?*#5@ zFWO1HBzSjCM4|tHBandG708Yh6f-DlU0o<5B+wRAO+agzc#*gG3-=?#?fnP4HWRYxpUv}ZtflHk;Unrq+{@caiUl)-oP4nGOdqNWml zV%8IA@Cta#R*(~r#1@|$`#!iv&!_ePTv%;M@Y%g?wm;NOV8$45JznAPwF!dgiEA=i zPT-PMxMxZZU?*DIKiHhkXn$=0uVUB2{|#8K4Z=@?BQppWgwk3)P+pk(0n5%wPog9` z7mYT&gnVVQ;Y6)XdFXEdIj~_czifiEQnVXal#wJjW;CDT$IMT48YUvQ#)dI(sLE=B zOPwK^Rf0E}GMka{Dl2%abb4i$6UKjqVVHWUT_;)K2b+Cg+q@M$jnATkFbQ6~*68E) fG`x4Vy)k_8nchEN$6O!g#gSW{uO?c|#wh#^>xwOo literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/encode_component-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/encode_component-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..13d93ea984eb0aa0484bcc47a7efebe4e6901e3d GIT binary patch literal 2237 zcmbVOU2oeq6z#*{q#x-vpzFiB0T&7aCzvC9El?~{5;$L8wJt^BrhS-^8I(j>LL^b+ zN1Wu>?~64apn!RrMJW(Yp=1)OI~v3;1PSV}tEaSI zv)S#N59Hc83!Hb538=6(je8)G(*s+fP(ngTAz{2AQqmZRR+rP6$_ckf0U#wk^o*4) zF)+kj*gR&YzpRXM6;o46D9)KGW0V-gUkWK$sAC9GmJ2F{y9F>}9HB{3<+NwpbHeSL z!|gu?+dGb>19PVG7$TxXgK`S=lJaYrYWz@1Q!}U7KNrvqyZDXeXDM`Vx&0!u91E+FSbw17FH)N%zYES=WkKIq~QDe>{?M*70)(RG@oVvz` zF-?fdrNw%0i6LukB{T!&m*|!%R{~VI_+GfTb_W$8DjH=;hI_Npf*ryxft1r^&q<}M zyncT^pSu~AiOcw`&yz_1z1jKYtt+pjvp*gkf&SX$Xh*sY~CIU?TVQGtPg?ZfqA-&su=?lOHY-!5tb*vY{*Y}N` zXswpNc1xz-kW;C6*<69=X4+Py_7=Q%)2$6{Qf~>l7C572ceyoG`*3VJBGU=)+w)Ej zZiRfyQvY#pAMD1B*CTqh@%CqZ$g#`8|0#1ffB&)4=D%06J-vgb<6G30PkY{S*znc- zFh2QoGX8RMY>`%)-o9T_!CZ}wRvc&OJsBohP6Ovvo`rqVzQcXRGna>Yn>QG;B9qe; z&8rPLO*kv2Qoq(ymf%oIiSMYGh7|oc7z`$z$%Bu*eoy_?RSe4`|M}4Oza9h*+gv=j zz1Ewx-}c}>&4wiW^uS`PLC;2|3F=g`5( zJomwbX2o@Ibjt=K$;#-`AsaOz2&M-wb*HHbIa#rxgddf#cFr=P?0CK%4gAIP8<oJ0@b?! literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/escape-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/escape-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..18b0eb2cd85a17b994a874e83b63a0e7c03ff0cc GIT binary patch literal 265 zcmYMuF>Avx5Cz~2MKSdnvV@kRsfE&bzEE&zYtWDksWW*Hl6`JOWlNl7O8$KnQs{Ub z?|bhiJHq1d?plEDc-~<=xvp85x!^g5R(WK=K5D`5wp~XUg3=ZNjt2qo_usIphTKou zn%2SUYV8z#PaYt_(|}{lATPb57@8T}mc6kk_{ti+R{!jJBJ)C;ZCDLO=>`+!2~}st zuONGJgN&DQ>3Z3^F(x!fjn@4XMbXRzzkf{m=Lf<#(J15DfWAB1~X+di0U}q7<-p#BiBvp!JoMOCL#kZ$< z;6xGbH*LmQ4tRJpTN1fz8;p%}TT`K3+z%TfwMtyT*ME23h$LG{n#u{z6O;V7t|kN|5- zg<>EkcKIL5oD;EoVS;ub=vf>m_C}$kx|ISY?+42dWch6NojPG2+;A_nbg?(&ESr+w zzNW2Y6PejW?1xY@omP|-22Z7>ggVu>)fCD!2VwZMN;Asg)A#+P6MNnJk(Gv*<{Mno UytzdA)v?1@kTu~?oG9gg18;AWl>h($ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/form_encode-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/form_encode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..1e39ac7fc2234f5f5cd69226ad86c271552b5354 GIT binary patch literal 813 zcmZXS-D}%06vg{6+^iq4hi-f57{X=Hu_X3h<+iw66EG}ewC-L^FtRPzBC=(!<2$EDGQKJ>z1doId6!nCGE|jH!iggc238Wf|VBl0D?aJP~$V(Id z>cV8WB7Luo5yeCoJWbZ?^~9K;48UE;>LRdxXpt;tNNsvLHShm(`Hhoq^@DYEPecdC zsh9X)OeWHz>`aNgA+i}Gb0V-=8Z&KfO-ncL1)1Lz3hk=hccW0MW0*I{y)nt0!KqgB zQhXGfDpBFH{P|z`6bAa86Dh}NPPlaEC6WS^)sBvgibnhOPJgnDULx&*8G2h$jn>H~ z{-+ySlYuK~iVkUQG`84WTXei*>un5F4bY+NPJy1Z-0`5Hy*Ej>>|Iz3T#vv9am_eQ z{8P?~fIM$qFaVoEVL61cXqn0zO3VVtyav(c%Isz?>bw-4((5Mkf^xAA!!X-R{Ez25 iKVxjMT-pqu&BXXj@AycswZ6>DcWyU-8rIx04gUaArUPOC literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/form_unencode-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/form_unencode-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..c08a409fc091bce2c1597655df506141af9da0e3 GIT binary patch literal 746 zcmZWnU2oGc6x{>L$~s<9g@iUCEARk}D-Xj8~%HQq#yPo3UdOzO1Ecb1SGQWkmxVTyIGDZdFx^ zY7GUa7~kFyj1Sx5V3Xo$XA90siO)vlEvTLCFm^PyrNT_`H0eMYolPY^KkWGq3hotj zO%OlNoQ$hA_52zEy6_*DKa67H{$e>42+C5b%3UBMk!dJWmb+#rYN&!ZNJ)4(PD0l? zRbZGD%ir_;en0ox=T`A?$LbMuOSad@^c`LJ`TrzdaS*$&Owc14pLm%82|xOUphejz z?-P1!WUh_6Ll4;bFW{Drc>mb)ld8h0YL7=Kl)5#%GBk{6zgabyuyAZaicb^&7fkd- zKT8xfRtc1?l!E?l;E7K?;)H~+J>m#aJ%El-BwVKr)5skm&0mYZfNmbWC};^*QzYxb z&`xU23dWh~y~aTh31^iZt)*y3dp+0|zliWjQZr6Tc*a?=gs12%tzrvR4BJGBY?;X$ z3jP^&UMtz=#s@5ybzVwgTw-)yP%igT6lF(_?)`zOA3RR-#>I2u66uOf`DzT+H}4bw I%t7nu4?3Lh$p8QV literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/fragment%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/fragment%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..8548a03987ba4935b7a6eaa4b6b1b26a853469f9 GIT binary patch literal 445 zcmZvYT}#6-6oz*pu{!WVhc^=p-Hn25y-pE2KMDmWvX84GA#Kw&EX^rN%JAQtI(3R( z=H&1^?|Bcr6&cJQASYz1-e%lZP^1HKnD{59X6u?Ody5Eqj1&KIS`?Za!!pSUS@h39wNySvsd1{Nw#lk>jWok|+L9ifqF6l}uVK#yacbkRXCuSXyybIFoU3sHyFWqfpWu tlyzqqnsEu+APCZ4;-6jpOmW>|qEpwp=WcY5I6vPN_6)ja@?J7yf_LKnksts7 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/fragment-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/fragment-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..31c685c21b416f1266c17cd0ce486311e3e4fae0 GIT binary patch literal 401 zcmZwD&r8EF6bJAfB&!=-qK4`J+&9B6B+xDQTOoVQF4TQpEq>)cFI^ zW8mfUeeZkZZDF#$!vbKb-d5b!Sf&#(O#G8dvt7fLB|z@u#J^aUrRK)4TylWzI=TEF z2uU2nxb1Q&3WVu_TQR-wS^#HvJ>$VRYMHhs^$^Z~&pa`grCD2(@Hi!jKikxte(|)x zrbXolTA`-47KXa`ISI+;k8~rM+CK=z2N;e%wd+W8+i6A9XRC$Uz0m*p4-rODB_vP$ zsTBEw{oK6hw3zF>PlX`DM%b+8taP5qDveEM`(`q%vI3QL+nOxr5?_NLNC$~Oyqfi2 Zqf=L<=hkViqf_H_ofSdpT literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/freeze-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/freeze-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..2ea97628b86d3bff829414519acf5bf2f2141f1b GIT binary patch literal 414 zcmZXQ&r8EF7>0L{tZp|MUbaK17X{hs#Y1}O{80!vk+GeMl(hZ2#-&L~(uw=)O}Bxl z$B*yJ^SpV_yfqmupHxoBTz)OUR;oxwyifgMsR8zY2zrjGKbaSW24h$zfROc)UY*t< zieoZt+D!0Vk?|3=V0zm&gg98~o_Ne!mu;6-CmKu$LTp*>pExSE6BQHtl zr0sIS3q@yV%m(zKYbkZiu0d&iI*D7*)}+3oH-BedK*L@`TYJ$cbvAPpRl0C8f1?;Uq-2PRe#ZVi!2Hz4>Imc)y^R~C#bceCiv|AhAf$Q*yf0Mt(j~o z_WCL28`pfQd6j#?^GPT4zZ|P_hJ*!Pf+(xnf>pqQ)cY{baru@iG*BuFIiI0J#7LkS zmm&o(@W!EkMiubq*Ke>?R5WH`E~JFoAUxPGu6A0JNtox{IvJRALn;=_6x05aEg0v5 zURzCLd6{yZn%zVdl@z?RJ(AEU7mi);W?E3ST=ZQl|5^Sdd3kdtN?cRHhO_O3{+T94;wY)2F|3DpcD~k0t$u}-7=ZA`j(iv@r+b2yI(8r7R z!Tlp+73xgs0#guKlbMQtVq)DdE;aIWK@(Y)zTHn$iifK`?hl&hR)B4d93QvCN0+be zU4G>zzlNMrHjR~F%Qa1#7#u;%?GQ^oP+1Fg7Th!+rq>$M_m1{XFypnP-63F0bIVMU zV}WpR2!3vD<=;K&GI;S%dxMciTk8@gtIn>Q)obEQn^kmOvyD+EB!>RB6!CyR-pYU` z)Yox?8IDvTY?M=g6tsylt%}IHi;7ehCCcrYHBpRG&49R|Shs^9!^=E`?xG@F&nZghv`}y&`#2Q|X`8NLY2K2g4F7x6O%e6@ ze(*f+`#bSAWVn2SoRFFNSa4fGkq*Ua;`b{s_8t-R94G#0Ruq~W!!pSU*({UsaT=mH zCWEHUq{xAcj-Un8yS5?3QQMj;>ybg!Fl|lh0lE6U^TssWYSvUJJWEmH->$ed*j5~O z0-QtLfN~66f_80Tu#-$te!#%n`C1aH#=c>gY>`eMhm5Q z9A@6{y*F3h4yKzIEC5#Od(CZ)WjYnZ#2?jYECKQwC;siKEHyWV<&p#JHp%^I8Im}L zN!#U86bQ33X3g}WYXKayYq+u=Orn-)Yf=y4?*GjP(`>INORk1Mbl5Kh1!47OZ15bq+<9PI<13vpcCOxr=yE-cx8w@<*K=*15+x2i=3PhJ-#ed94O%PG0vUT4 z^Zjo{--{x)R@G@CGtG7u1Bb#q)fHnjy)IF?4qFQ=VVsS-n(hA9jD!($BdXl%ug2tl zI?1JlvgHAKSporJfovJOL4`(Ut^WYPV|36q4g-}noQsI*BcN;X1`w&`0_;(qDW=Od4t>sN%Q9^w0 zj8yX@*mpXy&OCy`m*jJQFd=Aaz*l2NbgtO| z#w-YRDP5AIn39=IW=5BZYgCDzC7D)^u3(cC3;hxVLA=EM&BLD{y_SEQj@=<+Dxz$A Pai=?NN>N-E!rI^+oyxSN literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/hostname-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/hostname-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6cc3c103e00fff2105af031eca2ba24843d6aff9 GIT binary patch literal 524 zcmZvZ%}c{T5XF0tSX;zP@uKJu57tYYiypQIQ$HdB718z-By5tYS(@yI*-h2|-c9NU zqPH1%y!V?o8{Ih@JYK1kv8jB&LzAm48i>u%-OiOZl9%W(=Q;@8gK3r#YR!`Z8JjAcbt}W#hCT3OO&R|`hLa9=%}aI{%_3#C;mdb%ALtpWV26a zxzJFyG+-xfF@S5Zsf^vAL=tHm5BQd1Wx$y@v(P3zFk$OI%4V4f* z84~j48D=@cS8FY!Y3{UFwfU^)FGPW%yH|*0{K?tWJ+4WNC~5qe=c`hfI7gmYOC2vr zm9c45v0B8blE!we;{*%!>Umz&3Ej=%NsG2?zu2{5b_vqm^#|@1mAtqtxYphW+Rdhg literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/inferred_port-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/inferred_port-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b67d6c31a6f7009f90d9dff63acb3367b7fe3c8f GIT binary patch literal 555 zcmaKp&uhXk9K}71+Uae`F76QO!R?}j?G!I{KZJmeA$lsKr0ushm?kAjaqh2QQa6SS zc1(Ery!Y}h{4E}=pJj&eTpU+mN}0z4)+NCe69p&*c~VPdJnX$JNHCh`xdN?e$^ql; znvBj>GjFlL{klmx%OoD2z$>cuO^va2X(|xL$Ni|L%IMga_~u;mMit#DT9@AJGWJO@ z-IRcSJdjI*GFjD9SPm+rLZ)OI*&q|-&Abf>mK%3bwMEc@agKyk73J&`kdamnD2IYJ z+?;491~|l6Bb}8{S;OL+_TcobE7M|Z5Pa0O88iHdbPX9R800oyi*+GfhCiJiITiaQ z6VQ>fp6lh2;674d8YNIngn=EXcl1xwmWz8)!8nj$$XPn2ze7wL#U?6s-Z+e8#Y|EH z&6(Kgq)@U-jGHTwMUqKtCX7x};PMcLVca1>_x8>`jRtmK-%}c{T5XF0t^h-RIUMd)(2L)|&-c(Js4Fs%|(s~IJHp!$}y4el88;bwEn?xz< z$=mEQ^PBhPopiQnu%7c6p&9#Fg35Rj3`pCz&PWkPSVHn>AY@t)Me?>*sc*EH#yo)sr2*4PUH(t3)?#dY z%W5!bwfvjIwPkT25^6{2)J?g_v9eLmO$i0x8c`BW@G+7}Dacqv6%pAk&xr~%zzJbH z8K#2gp{jxlc^bx?DIJFlBcS|X+jh|Mt@iazHR=v^(j6VHet7Y)3F)<3P3sfcpQt6Y A*#H0l literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/ip_based_schemes-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/ip_based_schemes-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..28d22bb8ad5c588896575aff613506cefdebc2d3 GIT binary patch literal 463 zcmZXRy-&k15XBi#TIj-1SPGJr1sK|7zD7|hpi+h+RJBuw=#n^%RVTL2j;j9mxE}~1 z#=H0K?&s(0{u+kMcU1t)+QWj|T9uoj=%xO>&{>X#mzgPQ-f-iA_c2fX=UG`2HwJUb z0oKbD;Gc8q%~vqcT`onTV07NUK-zU0z#Z!v-r7D45{+cd##8Y4*YkyhTS8rX)0<5{ z_0uJ{9kqsG%a8~UOjT^xs(s6Z9-lDT1#`kyH8=dHWcHv%fl?lrH}zJj|I|4VnGubU zNX$KeRf-z8$Z=GtlE*<1IUmIkX*6c9sEm`SR>mGXifrt3l4Fgwj-%i-a$FC$NhKst z{gD)TfWJuv9f=9$Cr_BDM%b+8Sc-OQvWirb*<+rWs>zoJ+M2!*Fwz`n{Le a<7jf{KA`WAT`?~n&Y68WdX#U{afaWp7MDo? literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/join%21-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/join%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..53b83e4578a0268c8bf8388eeb9c9dfa971a82f1 GIT binary patch literal 526 zcmZXR!Arw17{xtEottm} zmha=vwu(7R0QVZuoQO@e#aL6Tf|jaQu<^Z$98=jS+2D_Vm)(GZeCeQPrz;e@n*)E6e#>qf|ctbIt(&I z0|k-x{6x!~A{`AWK*kI0n96G>?{W{cJwa6^N)#TF8h}yK)NqcZx1OZ*Xn?v&lLxoG zjB%>V<}9|!zHqw|Y$W3PkK;kXRFqSa>NqmW1Qd}nYl$F>5-61}Tt+eFuyY(IJkg81 e*ZK#e_OA6RTY5Bo@sq1&6K}d?!e2O%()k4d1Ec`} literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/join-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/join-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..f344b721a7f8c511f7504f638ad4e69c9b786079 GIT binary patch literal 762 zcmZva!B5*T6vjDBp@nuQv>n*NxYAUnDzSuim@`mdTcw~eO|0w^p~y*I8xJRrY=^;r zKRYd|2s=i3@B4k9-}h>8Ll3UM%AC^k`tb@(DU0NQ@5XreNAlXE-nV&-56_E2fz~V& zKOB^OGsIQmiSx zaF}>8KDx9}jWpbYVggx`MnvgHSn0@JD* zC4KNMaw={c3MbZOie7J5#}PcRsu9px3P%n;j4{rb26T#WX-q?dU^C?BvI=nLBgQ8- zi5=-9eft&~rdWZnY3?Ctm?`n`X6gNlac6Goa5H2DpXM$nr)OyLxj#+GL(a03PsD|x z|1tNBdgelfV?y_$B^O|OC3qIFZMOnT^i|fqD~V*qO1QaED-q4hEzwZ#BL z5$e@V#%M0kaF1DF`PI}28D>)vt{v11Yb>=&T!F6t_Pk+gu#Cm;Z;f71^P^RE}mNk;_kFJW%Aa0QchEh*oQ;j!~E9BGj%EkEF@Bv!_# zK)VjyQC+r5;l%+s4JFZya--dFdkL9k)leq4L22=G#6Z(+*FzoCU(B>Cm=ER0QYSOf#aC0I>A{u2+sZ3b8ij! b&X&S~xs+p!m`{{n?vs8Mvcl|Z2Q8Mg literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/merge%21-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/merge%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..3c1be3b1acc72b383345b4b9b8d5710bfcbd52d8 GIT binary patch literal 537 zcmZXRL2JT55QROI)N1KTN$GY8W+79b@HGoW;{@`lH< zW6bBYTUKGlBc%NUYRSZ|Dk;_6Du+U~Y1b{8P}09eI{4r7#RS_5R;Gq?;~Snint@cJ ziWL6=lAy>5CS(#}3@?r4#A@DS!!gzuu-A+gy9F4=;!G9p8T zL8@!tWSs(uFfXytLrbENG?rw~RoWQ3cPFmp3Q(0Oh<}befEsB`bXFHq;!1#vNe+?L zd(n=Y@C-b&pYhOQr|7Lp@UaM+9^1v7s~`my^I|K5L|`7M`al6DL4<{>mk2`0aBthT j-}21Plh!}iYWG1OwXJ85gg5Y3^ej@?Va^x_@{<E6yjPxZ^$)VWmEY+jmIsS9YrGgxlZHRbyXR%77Il}+~1`a z`@gGby%v+MFO)1<%=SPVG!K0zgh%aL(rzRsNr%SS>;sF>FK7Os!JWabiB{*?c^ZpN zV6}kYN#IGk#y_u0uISq@w9VCGcmmf@a@(=?@OBQ-D%z&;&9;#i+Q9=fXrYpIO~#Kv zK@C1iHc%UG4|xAr>I2>!y!ivl<^&9#_Z-%x2G`JG&m$jocw6WR$#|(s0Y8#4vZ7&n zFKW$3?xaTbLh#n3b?D6<$-qn3?7$g9M-|wPN{LE6&jZez+`cQ+54Td&8L!46yC{us zL(14f7LvMz*C)G#3&(j-{}%%Pk=lY|ADhp82z($+KAvzFi6Pe;4cTkRJfjN5Qcj|+wBLHkSY$8g9!%;infusAO}QBVIdMlsBF2cs>n&4#%*F7+tF%; z`0tFJY*us?R4IpX;`jCV$;><$U*f}yk0QhPlrPVzDMda%WZSVf=5#T_qffKgdvcoR zifT>Lieh|u5o2sWhNI~W@5v^uSSIjM>vB%iZ6h%T%ciE>jPYJ1i86YAAn?fcxeI&(sq%}pelCHx3lnJs2#NL}>b)%_rS{H06 zqhX~aS}%mkow{FaIJ_8kutzdph?c?~`ah{kiDC6N0Dyn_#olivSaY19xIm_48o{F* zDJw>EAKtW^5#c$YZW9HT7RIwaMUCo48eX6ev{`yHguHjVz4kJZP zqoD2X&W|f+kqHhx*kn*U2!=}6>#nWwZd9;}#@0L{tZtx}>17^b^`Muo;4QsmItv9SGPYBZlD6O0xHKtAs?5LMb`$3h z@ECZ%=l$}02hM^FW)qbWGM1Yu*h1y;fOjMJSSnpI!QbH=5p*9$E*|H(24h$%fRM#3 zy7(3eP#BVaRi}byiVSziDbwq^BBbHhB}nU#KCPIxChjS6_A~RuG+Sv_6(~52QRI3P zFjm)@<*y(%_^ZlbTX2J$daTkH$gGC~H2;IU6-=%lxP*=hdY{M}s=?M;;`sMZp7FeZ zeMjEnw_JL(AHSpq;2#O?9;8Q?TtMUw1y4t8FKkq6?&)-!@u@1gO$uN+mn)MjwJHE0d%k)SK`7aVK)SSJ&+*J!$UXG|M%QFgx8DeB2)DPB3Hq4_P;p+5i9m literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5aea3c77262a73db96b5bf5e50cb916bf1a643ed GIT binary patch literal 740 zcmZWn(Q4E{6zzkg>lXS{1X;mLL{yONf^V}gsoKRrTV>fk1qqYM&1URmCd{2!*RS_Z zx>{NvGdcI1d(J&iCfDL*{n;rY&g||IL+k3|L?7nqv30(aM*qe{Bb9*JaS zP>Abw{^}mFOjav#)DM->%8A(>;idF9LoWog4;|Vt5l2}seV}6M#EXZRZ_>-HmwlTo zpB71;zFuP(yd{wEPo)MH1y}t*73Rq@+5E@y(MWr9p)DS`*id*rqu-9 z=nra##Iylq2-x)jf`eu-W(UgIhHb|O>QU)ND;c!2G>0gdr>i^w{?Zf(jPzUN8OAE- zJud|=wCJHn*Bg98&`50tjx0hv${P6hp6AO$`u8Ah4bqT{*czpQTOC?ZQnlJ{K@$zk zL)t0?!k_3FvEQiHO@p5Ejq$KYxnr@OW#dy+B-tT9ksCZuMhDIgsD(9j zg9)1VhoC#8G3V@fA15E?L*~cJK=HT^-#KG^bggk*OtVHC%+s0C)v3I1(dppz+*i?u zSY)o#p=>!OHcVyXT~~(KwbC^u-zBgeDl0VZcClC#2YGt<_FWv!o^v@T?43VW>e*ed MuEz3yGLmTV2L#6S4*&oF literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize_component-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize_component-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..456c69b61975ebbc0ede9fa73b726f673567e485 GIT binary patch literal 2534 zcmcIm{ZHdY5WOF&K;f=xrPH+%{TTVg1xkq1Ym15lD14<&b)YK8U8O@b+SudR!uGnm zYXbcBon5aT2(+py^@j+VUB8+4_RU*=wD`_@K0M;S=j~@VC#WJGoIj5j2F@257b#2P zTO9d3&3T5IYIu#~{=oTmKL`X$$;JtK-n-$z^B&vWZS>E)<-8atvCqAgvdRe)mqqS* zRI*43a?xAv1Qj7*=JO!VCcr~rKz%^n zX}i&FoILa!fL@w#Ya+!iy0W4QL%gQpm4k)RC&EyE6Jf_o*I9oIY%)yCPt`8k%5Q)LWVM!rXOLRv@#V}wvEtrP~pB!LQ? z6bTa+=ojLn&p+nbtUEBQ+OT%SO?PqTCq;m!k}QPaMP|-Q{#g(Ki*z_9NiI>z_BueH z3&3lZ<_Wee4QIT0d$9STv$^e9E->Xq5`fPNS%Dnk6^a`bX(x;eWhy2}%?k<5ag&~@ z_#}enZ4+1)nDwkk$7a3Lw5`0Uw{6oaT#N8e0+**+H8oS#q7Ae^uUJx`W#XRyQFFO) ztM^JW5xcTFv6NgLhUlv{>|3Y2%tTQH5(ZSR?gnAe+c?%$7OqM1K~aG zl}_!<2GF@bfESP;={quEfq@yj?o&NrO9SWl_Xsm9Y29%-pOq3s^wFWx^eY}GrM&kF z-Fu(%#O738MeD~D$jJCvV9IJ)PUeiK=RVOhUk0*9(%RQy*M&IL|G5E{=g355-0JWx zb!!RWBA&zYZhc2SZ0jG_Y8oYmK%W1)VidY}cG5nAdy>t^UU)fdxP zBFP;pU+vDN;a*SLXCG>HVM7dP%*KXI5W#)RdFu zD2|bywnAPAr)BGYPMhd5V4Ju5n;+nnTQ4lrf?L(CwftIlN1$LJ`v&rr0n{EMV|q)y zkVb3ZtR(T+WwXy3w-9k#jP*9J)8lEZMiDZ7fyq%Qcsf%0<7dP}@>r(m7M7ziCVblI zbk3g)oNTT3acg!(mcg}^XW4GExvo3x>5sBS`aq$FzW<{9h&nZC IVPd`W7eLn~fdBvi literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize_path-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalize_path-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..af3f998df9b658e54e322339eccbf0770dd1b839 GIT binary patch literal 478 zcmZXR%}c{T5XC*nT3hjA^->QZAou}o&XY^(MQs-K5f@ z-gaT$Z{ECj*jYe-_NbNsWBEBnTc|AQ^P|{5lS-FN@GqnlvjqY2G>QGIah7Q`hNS`l z7PA=O&s<0*b2zCq-!O{`23z=)>2+NJxJ`A5(srO1RZLrxbQN6wo_S@Otu(6&5*{Zc z_U~qBl-Qv08Y9ND%CiM>?HOKH0*&=@XLU$IGXKZA7fi07xx@n%c7J$5vze7%@@6%c ztM?Y`%?sQ<9Da9F3yn_q+S^E@t+m{X8{KX`YZ0vqx>3#r#{NL?bj0?tjcUz@I&JJi z5UG+|S|H1u6GL;YN@|;Msmke6N$avQG)194f*?o^V!wCYq;S*7qjT3t$CcndljX%W N#h13W2f>U9z5!R6cqcQbdeb%lPP46ptjhH7h4Pr>=`nHQ?*TGOUN z;co@$5)&U*{QON~M{ITHKl(icQZ=`vVzh8@LrSe`V!Ql^DoL)S pb!QloF`?drAV_?OYHgk34FWd^ z$sn0z>6y|F=4eV%5Mi(ar-4hU?_j142t^=@JE2uH04m*Z!t+SB=V6}c{V2J*{UQ{u z>A|MgoMh=c-yLsY`rR3l+J(o?b>YD2+&Xg&tq~FTkyk&^6r`kCkB~1W)H`+S1;?rM zh%K40?I9^|xa&XAzqzL$OK$Bo7<8>sxm(OJPz|;{=th=jA-2V2xR*jX{)a2Q+o{{XI6jObA2y%EvYDr9O&IrjHUtl$$l zQ6Yt-p@COWEJ7rss1=u&{VhSBhcNhGAwi^+Z4PHbVwUbpQ5^G!wK}FW^h^;3+aKyi zxV%PQQHE?jGrGy0U%p(=@={Y)m9u$)l-_>7KV8ex*GKffyE^apaWHQ^;_#4`xI-DD P!+E(E*Dh{X2ulAC5Ef6< literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_fragment-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_fragment-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..efda11eb731f5a6d6ba7e9b8ce9909d2eacc90ca GIT binary patch literal 447 zcmZvZ&r8EF6vuavu5LFOBFsam7YDNS;=$KT=Z`|ciOlU(q@-=ShNXEWNfG_)O`S4i zI|g1p-|zdp6L$@xQIIt;>+3l@80!Lu3NYnio*PgT}606)ZUg}|q2ny21gO|xA^&=3lBDFmQSvJY0S-RN?yBkFRdN)=O z?Q!7E@4b0*vi}F-(JrLftSaK6y!NG}Z&}F-e1qMOkWY49g`4 z*sRj?|GLOa5*W8#E=7Sb-NTnm@46PiIdu(J)`xN2GHp%fBb@!!yfDqSnzgkT9cNw| z+^lO(`Us@JrbXq}Nrjr&S{ULIT$A4jGcWSi2gEzc)b2?rKEP=7L%oePx1Clbd$n4q z?Hf6?IUvI*u7u=iFqI;ov)?M_ofb2l_wEqJ*a%B&&PvBMw9?p6+ZRT$q6I4JE-*Cb k65qox%m!&Nyu9jH;}h4g?@n?ENCUg}|q2ny21gO|xA^&=3lBDFmQSvJY0S-RN?yBkFRdN)=O z?Q!7E@4b0*vi}F-(JrLftSaK6y!7W@`_;$0Q9d7GyC=_8N=n--N@ClzX9Yhj2>a7}(A%)H239}w>(Q@baj_yD8P5A`NxDt}5!BmQT&VH+ycUsJJ-n&B>VyTH(# lOMDN*FdL-7@bao(jZa*|zB|bcNpZTb<@x&$_mUYCegUf~j7R_g literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_port-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_port-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..97b2f611d67c75d80e0402b45c27b41a67df2afe GIT binary patch literal 432 zcmZXR&r8EF6vuavtZp|MUgjZG1O?gZ#Y1}O{80!vk+GeMgtSf9ur#kEDWZS9sS}3o z_~83K-|zdrlVC$8t0yQ3S?JHDa5a?KL=I^<(O?>`LlLEy~geYk95& zA)6Jw{I82qnv!wbU> zqZB3n-K^qx69VVDZnSdyxYU4cB@A{MZt*U}5QS*AhkTGsEnkG<9UXRmvG);h+k(RB zy9J>ZANU`iJv8Y?rI0-F2U27swrgY5f*3-!wkJWPYhh`{S>eEjmY{2D*PT&a(p)R+ tPB1j%Qhxz0|`J4=P9-@E}YssULxW6{+nh$g)W`&C<^LuaJocL=PEg!J}n5)kPw>6g8Nc7WStWY;hiZ5PLQ`EfS9(Yel8eGoHQgdTi zE;+z@nO+<#BQHr{*mk)T1;S)+uwZ)IwE)hoYq+vL4C9t*Yce0<{IBMfX|~aSyPl75 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_site-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_site-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b3fd00492dadb235dfd37fe28fb27feb327871cc GIT binary patch literal 737 zcmZ`%O>5gg6wIM0u5;-_rc z$}wpgdee$|^JeDFo6!xOTz$uy(i6G41lwU#O!$5tPbBJ|3H|_0X}E=mM(0@`e?Dm% z4aTra0Hrrq`KNzzizv(JfpV4LHPXW^`6bhLPEqPNxgMk)(SuYmZA~#o`tc=Z$uzsw zOm)%XZ86H@^Hm4rc?+qruefBEqa@gdr$XsD4Y3`wM1%4I{hKfngwIH{h*qBFY?y-p z17hk9dYBStKu?Kc#;j2{Q_`WaQ^I6J6l(hy`Htpjsd>*d7n?BKIzd|01d3V7j?BQY@y!n(bGCvG|Sg(W^b6jHsU*pbNMU&*|_skni6tms8-wyO9 zK28P{S)&sT>DWDZqg#uoTY}(vhq`CNL5S(U+&jWSbo%Z|TjT>vHCU%5DXy*N^7a>b zeTWyy^Twyn+s!WcAc~IDmJ7(^L&2+rJ(nkOn$L7KVCE_I+?E}%#_us@tFbR_s91?@ tS);V!yk!Lf*Yo+j*vsSnFGpcC{op$}@-_62tbV^O($Ar}XTl$K{s_D8@|^$x literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_user-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_user-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ab7900fffbb5b69b7f5def36f27b33fc9b0a5718 GIT binary patch literal 431 zcmZXR%}c{T5XF0tG`2S>Ug}|q2ny21gO|xA^&=3lBDFmQSvJY0S-RN`vl~SJdN)=O z?Q!7E@4b0*d11)5$lBVAjx#R} zZq_v?eFReIrq#-=lS(78wJ^jbxF)|5W?tm24~Tb?soj%Me4wMz5A`-iZaY*Yd$lOk z_Kh6c9FSoYS3>eMm`ah)*>4r|4#f=f-W|eNH^S1Iv(j-5txz}A_JvVh(LyWhE-*Cb lQon~`m<`fkczM;Y#wV^}-<{-!q&VHz^8EdWd&!ImzX1I2jF12T literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_userinfo-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/normalized_userinfo-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..683204ebd5e26487963d1825309180f0eefcb7c4 GIT binary patch literal 447 zcmZvZ&r8EF6vuavtZp|MBFsam7YDNS;=%ON`J+&9B6B+x32B?IVQF4TQbhlHQ>P5s zjt}1Ze1E(XZ%szaN5~18tIq|u6%^@6^b`L=fv%YpU%a5L;aaE?5J69I;!oy9p}8?E zlbn$CGPydo8=^QS!=}xo$bpP^A`7OsZ9|AtY-_HpM}|?uv^A**!eHm*2Jfv*QHWLt)O*R)_E{+2gK+RmzKb-styVaF zvo7f79UqrEpp!vV3ds|HEJZeB`&wqL7E_&d4oDC|EiA1#D;(Rh literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/omit%21-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/omit%21-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..06c014054c4754d0ebebe8e44b8c22b7b4cfe914 GIT binary patch literal 531 zcmZvZ!Arw17{zyxIydnkLxhROdQlHs&nZZzvrup%b32t$(l%Yg(xfD*WB=le6meDy{-X$imcgLtxHxCGJXrc4A|fX7snmEh(Q1!e^S zd!rU0Aq`)XtdT%xI}$>Y=vs0R9ok@FQ(f#6?XCZ@Zjd4b9CDf%tuxp`Ic3Bo z&1f>jyR?V3qyw2WJ07z1xF9&Ae5vAGiZa%=lUU?&D!8^DBA4=N%tK%?UlO_7tlU98!0W;@#Y z-($B$3q|Z`+4(&md7gEyVCV8&<^U(v>;g?Gi)4qb$9`7|W<2mdk7NJUNl_@&nr0jU zt}f%={Br1x$FNy98E3hK-38`?s@tXpu*^naWje4K)l?asY)g3k_nRM7(HlkU(i?UY zFZSPjx0;&dQq;1t-)b^dQV>e4$Zq)?4LD?kt4FIINK2#zt8R4a=8+mV%T!L&Tvo=dCe4t` n`!EcXwb*~rZ~gv#M~U|Aq&wD)J&g00i%EWSF8CRzT8F;@<8Jzu literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/origin-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/origin-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b57be0cffe6932b2b5b465d37186b0b2a348abbe GIT binary patch literal 442 zcmZXQ%}c{D7>9R|u5L$%m+cVhMPY13<__tlb6N;Ek$s$sl(bFPurw)eQbhlHQ!A)= zd_VGg-aKdS0gtv1D#Lgs-#5&ZDvw9JPrRW5e&o`@&SONp$tur*X-!kXFg|R_)%Q4X zq6iP`CKWtWc-%#8D4d!aW1HJlOd1yt!XN` zfK16XvcM_Q3^*11gXPF5wA!tSZBmVD2FMAVJ@LldXpNSOyG6U48LlK+&TePz@E`YH zPeXoGjD*;AZ?-8 z4^_oYQZky`IGq%rs>HMs6ICRclE&K6Ny>zJ^L;<=5wCxJ(>@I^taaD^+ZIuF**SYw LP*JfKRBQhe`tXWz literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/parse-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/parse-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..77bbef833122d1926c90c55f7f26a4378e188954 GIT binary patch literal 643 zcmZXS%}eA!5XC)6oE<&N9#&b3=)nb<2`qcq8j<)l5KviWM=wD_CFwZ5cDh4%2l2nR zk_^a>$NqS)ey^&wM-RBaxHbjig?_seer3vZU+yH~xFPFAfWgf?2@fyI(hBD&R|4^2 zksuDwvtYi&-KNczEDRnDPIqKq+6Iwr+gfNp!rhp^dzX$49{&I54_SJ))U1Npmo!Mi zUkl+|s~r$<88G=jQFzG7i4u$kzY@?_F2Q*#_46c{12JWw*9(#Mpi+=7YCyBrwBrj|ZiF(D^$S!GR~`ED07Q)PwG ro`>wRTqyGzMNzuN+jGMDADue>#``nkdVH7{Ux(@6ci8Gmk#o^Ilby@O literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/password%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/password%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..ac4fea262910ebfb061fd095b1c868340dab5d6b GIT binary patch literal 445 zcmZvZ%}c{D7>9R|SRHuK;bnrMyC}%kbBfUUQ7AZ(eVmGfv`yErG;c{#hX1{(Q>W-L z$;yducFl|lh0lD}+^TIS+Yt~dKJW5gGj~Cn; zY%7kxBshn<0p&Qj1nr)L!7juYg=qN)cPE+JJPE~n5FURb<4(?MoGz>uYJG!87O1iM z6)V1_-!?uO#OcWeDX z^f)l{%*=b@ZD6!|zye^d-j>|fSf(S@vr7(skt#MmmFZTO0K^f zLK4R?Y`a{F0%3gQmQ3%u7QoqE!BLpZ^eH5LH6* z#2-tM&)Cn;vrdbt&JSB5h_Deht2ry3XR=CTli5Qu8CF?=%DQV!mUD^wAPCZ4;`eVR bhtcTVMd`WoT@e=-#~7YaH%#737kKav3x$Cg literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/path%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/path%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e362625a841f7e38c205894ea230254397ba9cad GIT binary patch literal 421 zcmZXQ%}c{D7>9R|Shs^9!^=E`?xG@F&nZghv`}y&`#2Q|X`8NLY2K2g4F7x6O%e6@ ze(*f+`#bSAWVn2SoRFFNSa4fGkq*Ua;`bY7t9wMybDa32Sy5!?ZQ22juGa&KuKgt65W_@GM1%f4kz=U|VtA z32+W|1IjUQ3EH)V!A?FwAzJ@KJxZo_FGBGig#9nvLnmf6PFGe7wY|e*3)EQsjuqe2 zgJSJmuK43SC`dmlh2-viDY7a1iD24lG0|Cf1_>glg{2i|g)4zQw literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/path-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/path-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..07ffcc344eab423c695866283c1a60ca8f99e8c7 GIT binary patch literal 385 zcmZXQ&1=Fy5XC)|HR`QM54DFSrBE-L^W+ly5eU>$te!#%n`C1aH#=c>gY>`eMhm5Q z9A@6{y*F3h4yKzIEC5#Od(CZ)WjYnZ#2>ZH)&$6FocOn^veeudmP-z>+a&j=Wk})} zCT*8XQ6S9Dm^IUft_5(+uHnjhFo{~Gtw}wEyZ<*IOtZaaZB4>aN)rEJTXWi@X@O0P z%E@Vkn%Y_z>TDMzB-;zhlVs}fCKMlFIQ}KgBh7866-_^_7Ha=RFVQC&jH60Op7=8< z@+JH0x$Lx9=)8A?Ai_r2tmdqAER$6lo6Pp#$gs)^RMsUmSPQQU7_Ga_Ty9}q;0x}rTI#dGW_pNH$~Lr zmxTB7y)$o1hO1}D37M;pCASq6=}?>}e!l^29}q!{IPpjGqR`wJmPt;?c9o1zw;_sS zGHBXNiX6!31X?n^ZyQ1!wXM0b9vMUp)7GROkelCc-k4@P&6)~@7b!~o`!%-)+lu2( zfODuDP>z91(C%0m?Br7vqRl_lqhxCTA{6gI*#E*UIx(wpy0%)V-2^Af@*UR`Jhnj1 zJ68NakEV@Ny5W!ZXd?Zn6q36NQe-psQ)1R?G1Xc38xllN3rj1`3MVqO)KF8~^`cPH t9Gq8KLo+Vn5ClQmOZ>~*Z~I+`h^|~{&#mW%IKMu1dIeoG`6QV!!6)lXiRl0U literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/port-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/port-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9b7455e7162a4c159392eb6c4ebe0e3000e4a964 GIT binary patch literal 505 zcmZXR%}c~E5XJW(-MU^E59%RQ5EWT_&R*(QA)q45?x{#g+i4q2GbJA@{`aO`MPwnD zB=df6-poO`q4U)vmXzM9uNSZ_R@q!kS#;Q=wgC;EQWl-uRh0%~cp-t(&5E6mpUWUk z=~3?rDN3ZLJIo8$AFij=GhGMDhV&@uxwa+?k)HjpdE=Tln)hw6Jj_BCU94Lm1DcfB z^{Bj@)ToJVg(2Q{L4swlW>LBx9{jPt^~!YxXu?bDxRhU{5nE71sIg*Hj*<$&5QX-K zb0bvkRiopMU`Va8BNf!#NlUg|IxvgDb+7q*$<@cRP%y#eYzPpr=sMA0omM1c%0dJB zo$N;%adei{LIR6Ur6_Ls-+XVK77JYrmNZVV6E<&wS3)%=A9~B}u!S7!yhQJztjPHeu29@@kMKbHBFG2ltn>Jl>7{6?MnugXG4<-y2q<`~Uy| literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/port_mapping-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/port_mapping-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..3110575cec19a2b5e43e220ad2aedd267de1dc31 GIT binary patch literal 467 zcmY*WJx{|h5M@AVpbJP93k;{QfK=Md?otF)WB{S6oiaq1)MiYSSk`?yUv98 zhgw9djTm=*sbt0C^84-!+V{Q_B8c>wjE}{5*`f6=k62v&$GoA%oyD$=7AJX}C95_0 z-Wmr8ExH!Cfr_S;RZE%z!qnhfk``)euvZ=iYY;7>O_n^HUYBIu3_^mC z2Mq0hnVthtx`V5G9R|TGxxn@Uk63cTtqB=Md1ruGjGc3$GdAI*wFF|BDP7{=>GGCqw% zCyue#w3*;J;NcN9r)t|a7+Y>zGihAxMGaL(r!L^p@11w5=tj||a>9$$N&LGdGa8wS zp@RYCP&Xhg1eKs{pKE0G6DM?5|5%TL%IzzctOsHL#EUvJtx>u(ip$MC8XF+ms1GFB zjvO5;YqQl~<3WP^QON~M{Gs64l>WppZ55xWtUCk;5!Bp}iqXP4G$|F-#B^a1C`k^| s*atMpn1Edn1ZgkvFK@p6w;dz8vN5~%HCx2_^)aM3P&E}#f@&Rn0UD-?S^xk5 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/query-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/query-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a5c5cd9d9ba5ea532b5b235f7d2963e928299288 GIT binary patch literal 389 zcmZvY%}c{T5XC)68rz!`FZHlQ5cSaJJh`NP1Ois1wx=LrlWdx$o1HkjLHggjZ3PiM z4m0of=DkyY4ddk_mH>0TTL{}=m5t>f4Tc}Rpq&TaQ<4Ugc~y}xh8Iczte5H4aT|F_ z0;8@klq?Y@N6>=Pw(kHOwQq&CK8)gylQo%-aQXY@l@s3(?;0;U%e*wWUNwRp*sR31 zL+$jeMq;*+hB@P@7kR5cn0v+b_E~Cig3<6Bbr+McJ!zJ`S(1A5&i-K^a4?K(sf3HE zWHIAEQD;5LDHVH52xDxe%^Sfh2Qzt1*yeU$NRD-0qPFf;lNUnaXBdXrNg51pZuipo Y+%@RC-`$Xu7smo#kXo)D6gMXP0_o3u7ytkO literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/query_values%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/query_values%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f596b54018334fecd2af38265012c2d5877fac24 GIT binary patch literal 1050 zcmbVL-*3|}5Z(jI$_ko56G&_iCl{?CRb5_qaTQ4UQ4z!t8XGTB6BU*l+m0GJlL_sXbu4%y>0w*=6xE_GDK#i{&I;Y3UB5)7tFSBS z(RR#7R5({yX3pq#Xjr`X#B>EZW6%IWBJ)xfrU=ZWGWWa!!vbbX=78`Ps|;lPg(Z3j z&d50r$aq`;%S*jlKPnh2g)3NcA;3tfg$7;#{*G#4Dy?`iAKDUsP<$z{SiI*2+mWL^ zOVbI+J1Yot2rYvF^t6n!#%sW)P_SjR*(o?Tip=F&RomnS&fmYPde>*)F)sycd0cDf zXQpD*Jl{1G?geC2D?Z%9@ZbkU@SX!fG5{J|HzbMiNooxv)1O9w?b7~b^7`Va*Cu*+ z9D9j5sX2_SUxUl=^?ZN_Vc5t10F0RqAneE1Pd5B?!)N{J^k&H3{~?D4+Tf?wSg;$S zJ^MS_OyIm#vtTO=(fq%EXnNFk)8-wU6t9UVw)OOmZw5I>?b1De#sv$=q2TceUhUb5 zC86Rb+Vy45b(Aqo&3smoo%=}JZH(kBN@StUYE)6ogj~9=8}0<;;gjpb_tcj1ADeaV WnB6fSljK3Wg&!;x@k(G-xxWC-N<3x& literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/query_values-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/query_values-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b4d86fb9ebcb0b2c739a5bbc6cbdb9d53e0212ce GIT binary patch literal 996 zcmbVL!D`z;5Y3?|Zk!Yfp)I(FVFShi<0uK_u*R+2G^T>Ol#t{ijJ&eOks3*>?yi!W zl7H{+%E68cJ@mE@-n{o_X6HrYn(kkI<}*r%#bS&q;c>8^Zu{i*&kDsNyk}X3(xJ}9 z$R}hN#{#8fQHGRWU-}2nNPTBCqRq03vUJ92tCk%zaaWa;YL6<%LN#d9E16I-*yHs5 zbIx}r*sWk?;`Cnzj!#a`d2x@L3o1ddUNGZ%$qOw6iUWf$OeSDM_MEHUU@;!Fk4{oPa=8i6T^s65&c4)fg;}QKkap9^9BgKwe1&5dx+OwwU&G4(E#QdUGyvrrh;lOY6YYbiwi`HdEcaR3a^I zLC2RE1Cvh!(BhU0Jo1LbhBk43*JNw@WVpG{o>lIUk9xv` zgOj#O1mfV79QM|?ZJY4P*}>og{3e=DK)=W_=>pMpH9E1#)YtfwJTB`-|FqTuZ4<#- zZy0xMr-w_OuJI278(`@?>B0(I@5yAzzW9Gvvyms$)<)BH%ttfa{+>&Bym^|TPg+?T z9kJEP991IiiO6o>^?07DFhLgUjmmH?cpfTqSRtQ>GhQhD#bp>_#vfeQ4YqvpwzKw8 d2R4t9@(%Q6HuN!SFq*xoFY255TABUd?jKHyIH>>t literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/relative%3f-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/relative%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..362bb385b7c27296694d778e8de9fc1972b56d61 GIT binary patch literal 517 zcmZ{h%}c{T5XC*n_Dl3qda2+N1r?;tc~dm4H4v~OrS%ddY?4X4bdwFc8;k$Fo2F7! zyv@Ly-@JKq++33Gd@5o>#`)(A^jaiAmoMzz2wBek z%Y(u}o<}-G8F3a1(yxItDmP_8h@qDmGY*%DVhijk-%U3E)rN}~EJtGup7>it+h*cN? j7hBu5gCpN++}u{9ZqIzLY2q`D7x(JmU#iu77l!=>#vY_; literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/replace_self-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/replace_self-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f4e1d8c6418aee67f3421bfdd8ce93c664fdd3b1 GIT binary patch literal 610 zcmZuvO>5gg5X~W|u2Tqskc)Fz)I*z#Epl9&qO^@cP?uujlL%rgjiSM;U9r1z=)cdb zTnMRi(=u<~*XVS#k(cYArj+td|6QSPOqE~Khb+FZ*eNKnaH#4?M)%7sj_<0&PL&V^ZNDioX#Jq5%x&>R{5u0Zd8k;W4<9|zM>7Oz4) zXhr^iTaTi*Bpx^k`wN2q+7pYQ^(};1%!bb))1a81zY^c37JYB^d(1}^!?ql!H7U&E ziK6WcUavP}CsVr(nPifhmVD75RHUC=QCrg%KHRu4bx|5_U3*t-QJLo?N%E5{9)IQi co3Nc;@qaPmJp5ReSBG={Hns)zLvfSI3nr?^MgRZ+ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/request_uri%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/request_uri%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cce22b37f8fc297da843b540b4d47a6ce938e497 GIT binary patch literal 453 zcmZXQ%}>HG7>7BSI^m=tT=3A0izWni?qV`jrc1;S7^lTF-PW;&uAOZc;(u=^B#Ip0 zkNlqZeJ-30>aU(-)UJIixLwI(U22yIr; z=w!(UVTgKllX8|xG(5yEh}tzZLYC1~R2T>Kf|@9!6Gx)k)14(zWUEMB0{f zqoFA&e2wEJJi?#_!$K-MV7e_Pzz6YJ*dr%m_r?V6NWXgwd}-07g2~z_CbnZZG7@W} zKA@m`{O1`MTd3`wfqz)28x)Mw$Q^Q)PRXy7sg*TRX?qXy0$DMGOG3!Y;aKaE>%VN6DL}G-!!6=8~^|S literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/request_uri-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/request_uri-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..53a8fba786a567bcd6eaa4c206778f6fafe650fd GIT binary patch literal 474 zcmZXR!B2xQ6o+>(47ZEX#mhWYyy#`)TrO-=B8f9*vJ)|+KpD+Si?1bS|Gh0U(Z!^P zzUIAtUw=Jww|KI7lm*5MaadDb%QBs?VeDN1{p_gHSqIF)&Qlb7w~Mj_suamN#dy1k z@Ba1#P88vB+vS`U5>Jnpt_keB7Gp!`8Y;Al$6-rAtJIbF=CtRH0NDX)YbQ8QjlnXh zDSA$lH}r!+28k*ONY_l+Vuny+w`OV6+Y((PBFesS0w;;ROY;UeAfTJ}CfoOt#eJPIquY3xlo%je`bxw#2+ z2Dx>?ekdEJvzn69_^GS{*<{-0o5?CGq|hcamF1MnFW>jmLF^6hAM9v&Wj@3;8JHp} Qu8&E+N@xgQaiWy}4dC0D2mk;8 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/route_from-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/route_from-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b7a8be99f605df982e876e392e9efc80ec4dec50 GIT binary patch literal 779 zcmZuvO>fjN6zl<|OBV?a6$gsMQ+ffZ+RfQpp_Gq>R4hVE%O$F!m*i#Fs^b@Ir)c^0 z*omOfBIOWUZ{Cb&=E3Ar9IoGSCB&KDt;lV;&JX2&7C$!JJ1QE(Z6u=i%PfYox;A7j zmWqV9TxZ9BjVz+&QcSzPRI*}mG_G8sx$Zk5{QkZr?IvQHc4(Z;;|HY$FU$X+gWl4JjTX^G z7JsmP*D2|7VFE26lxPRA-(*?!PO_fCZ&uWR<#0^{LN+iiI@eSM6U=S~7lF}#)HGBD zEowK&<*s8Z9R*dV71#87bjtDRd^pa+u6q`|QK+v!NlkmaI0!aGS$rN0!xr+d&PcsE zxfj9-96K(oGgr_X=_QSN9mBv0A;5tyeR8|?MQR3jA-|jH)u`-FfZxcJ-t2aN6!kH% z{4a_>?gvx8_wojnj~%?2kRltoks4JnbdV$-r6D|Yi8x3bsVIw&lq~0XTeP`<)XbDY zl}J)Pv38!!79}bEkt9jJm&FG!J^ocdr_X$aC!X0Kmetd- Ne4mFpy;W#!@(Wl$0A>IH literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/route_to-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/route_to-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..9935b81e39040a1720b18484e0e3e9131bad49b4 GIT binary patch literal 775 zcmZva&2Q8&5XE~y>9PwFhl&HOz)CM5Rl7NRE0prFBGMM2rR5S;k&{dstBxnwlcMFX z$9769wn({T?0NI^d-G&+$qzQ4u;TnoZ_j~Rtn&l8pT*A&4g>{Z#G}uvEPj1f*9NQ= zr2@_`H`($1g=Mr_@mW8VN><1ZN4axhZib$7r#*C_X~Jh|FAUjyhWzN?JKuy6*GBYh zw0xRRvUt4#8jQA#T41(CLtu$%G@VfLH`L645+rYdHLk|687~ffucSM5aIPSTMa$?S zi@yvOyp*)zL|7(RDQswVN*2{X67`(@ohmdFWhg`Fkj1=U9yH&iCb-M;U9qc?YbU@TU`l6pw||G^XZ$aU zd)K`wKL>d$l#AUFJPIcu@n@+IPf)_AX(JV6@u8CCLOiV5!aZqjN>9a;6gx>p3!-*L z*uvXckYC0Eo1#KZZkR1fQ1~lJl6)_Vr*B>VJKvqYatl0hfbM5iy&RYCYgng`N?4ox E0gs~o!TPgv`yErG_NEn!~fpYPKNCG zc#qHL`@R?M77tgikYPNR-%Dmn$de(zjJ<1}m8@dV4tCz6*n61gxnf$=R4|OUt9bmk z51c5%gStrt&j61)*pjM!Q)6t&O~s^f@gS_JGCFYq-~Ye)q>AnotxG4kN}Sl6teMfs zlniwWltER4v=mf;vJ0+}4KQ^AXLANy2rBpQT(TYn{UdPEs%eFiwNYH|CTMJcXrsQ6 zWCwDTY^=|YXU<;@?uP{zEcQl%r!#u0V%8`=RcRXq`yo`^kdo2dS~MvXRK&D}5hzFo t(%2U?Ntu9y@B2wF_HG_e37%R=cx$_M?RR#Fvb(OR4^R~qFM?|A{{Ztii`oDH literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/scheme-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/scheme-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c5ceabc24541ba4a1776bd006550e9c1263361b8 GIT binary patch literal 393 zcmZwD&r8EF6bJAfB&+L9hL`OS>On==dValh{wNfj$lOjvO4_DtSejRo6!E_|bpsJS zKJxN;?|sj_9ZWZmSOTon=bGCFt86O9Y2cf(;VmaXo{}_}uc}IOV^|?Mz;2UXot`6- zB;a>_Aw`KWJ5p<=4}AyV+`i??df>+$)7E4j!u)s7E7NSRS=W&0JR@mvy=^!>;OfBu|5x z6vdMLT)XVGSm0L{Shs^9!^=E`4n#q=p1&e=Itv9SvLB}+A#Kw&EKN$1I{fcVH$}zc zmoGfe_r53I28PSI$^mBbW5H~tigd_N6Tfe`W%mfsQ=IstSy5=mUE2USYFjgDJs3m{)z+k*f~&uOUa6*AO`8gZXDLej>lL#G+lt{% zfZwTT87`G}PuyT9o}dt||6v{kmAhvySx<%iFBEiATH|zOHJ95vJhqA$tKYC>dvd_9 zoyQHoTn9Y#qmm2eVhf&4=}+`&tNBD{-3bsxs^*qdj24b=NU2p#Y*!FbCCQbvF1jHZ n6KWp>LE20F^P6w;ZHI_1T(h3beKjRO!`|oRK zch#b*H$P`)GBbW}CJ*%F?i)6gUdYWY*dE*RgdZ01k>M618eQi_{NbW)H5kKc0hB)6 z6`#hBizv_Ov2wNG4bs!C%q`PTPEqPL-2l=~=y9f)wx*mS{rDQQWSTu{rut}cR8ESR zu6iI14mFp|a+CzSFe;Q@$Pn8zOEf5N#m|J1;9^dqMYJm7>#LCm0S3f0Jq$1-&VZf~ z#f({_ZfB%NV`qfPmMGNrFY&$1*;4a?X)ZQ_+c`lx)a3hWwH#UDa6b=!{3pz%VDjmP zOE|#AGz9V`-sGMPzu2IJH*?-#3t!^iT1As&cRlw36UA)*_1S^m#OKL~B5QP_B|Uoq zA9Ne>aw`y0?@=#II0!ZUS9>own$F(tyhXn3OoMe=lJeeaE+2oAUHh-<=B=-qcbk3N z!3mva9T!lnIEVJCa#2k$@DiRÐ^ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/split_path-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/split_path-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..df967e999d4fd7fd3878b239b931ab2aaecbed3a GIT binary patch literal 577 zcmZWmU5nH(6x|1@X3AiHr@l=*_XL`E{+a~4aj>G(W zlU7;9mvEBad(P=OPbRnOUmH0Cop<-I&xkDJ?wg=qQI_0#}jp2^gtZSsaI$J&inv^dxG9% z%V*_8%h`1@5JYky0+V(3Vs9gs3wa(|2xc}H*)qG)@~dWHgV=f(Y>kAqU;`YFh|>q` zdOrN&fQFGo+-EVch`mAgo9N9ThOQ2y)G#nlBLCU_)Pj5XW*r{+7cVz+McA4TQzZ$G!IjA@9hEazzA(599jBJF#*C(u?p-q=>nVfXzUmrbT00 z)bg~on*}_!v)GZH(=dEvX*qd}-+f}v{2cNM1&E8kQxGLF53YJ;uc=XqWpX?c8} eVwk1%;&m*361$F<_4d`+*mqAIv==eLkpBYzQn~2> literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/to_hash-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/to_hash-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c35afabdecf8c3eb29603516055fbdfe822120ee GIT binary patch literal 420 zcmZXQ!Arw16vlUuu5O-Wc$q?|7xl39oDS)n77I>fY^Ne2ZPPU@%_~WY_}`ms6H#yP z@!tD=-}_Gd4IZr?p}=@9KbOqZP-Y|EPlGc9q^7#|u=kXt!PUGh71NsLf?>Q_rPtr{ z$V(DDY`a|W0`T|%TT->_T8u5ZYnU`X9>y(IMrS_Y%ilY1RMD-XZS6&;nU@B4D`q++ zHKOR*8bDAXQ!`{WQ2|X0((?4gi@fze)PtaM_rfLXK{Pnx=CRuIQ08dwXnkZ+Con6Z zWcO|`o9;`e_D2N|;))BF24lhVDgDV|+9^I!xpRWU7#eO!&1lKxR+CCWLySv{Kt&3W p#`mBjn8eozWvTNNpW$=<`q;!#X?Z6!!H*$g<}8! literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/to_s-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/to_s-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d1601eb5b52a39a6757058f920083d902508b39b GIT binary patch literal 534 zcmZvZ!B4_46o);SF+eYbcn}ZGJg67gxg%zXE?FYRAeTAaB28yIFTCvx*kQ#?NPf_e$PKrWvV^}6RrOSDIy?YFt zD5Bk}&ZNkJ4)&NC)7!eD6q$9&m33)1teCbYae-d_{`1N-TWeNroS>aJu{WB6`r!DN z*bOI`Lo5(R#yJ%H{>^Hk*5lD`7&?Ko_``dUOl_Zq;wKPvewfoxb6aagl0D#^EcWah z^BCmqR<@N=P1i11Yi*JGvOvS`2m8bfJC-rLgISvjS_Hbfuw8ZDTBj zRhomc$TVrjC4Bn6pEwCh?lvB+-YpZjZe!utJVpUnl4(xX60}$eUi_+T4l>9@B9(}; u!b=ECFby@DL;v6`>;>n3?6q$1ny9dcH+7MYLzG|aZ}I}VWO6E*G5$A;Tc^SR literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/to_str-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/to_str-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a6158904bf3b2f8023e88b495f3c303bb1c6af9c GIT binary patch literal 347 zcmY+9F;BxV5QQ0#8>qxov9v=J24HD3Un`Ufh~%LNm3GQtIf;{6IJxNTfcW=yS|r5y zbnm|R-es_d$@T>cfOY$`QSN|cHqj#hyi=u@o2U#OH$U#+$ezkmf!uJmn=O O9`%OQNb_u@webT~FIE6y;$GLWl5uhfNK%8NHteI3W=Q`shP(Vfyi()45rtX8|JLAB; z8fRQVVaI}kE+Ar1DV9JgBsBDSc?S$pm|WdgfahtI=LS~w8nnwy%-I8zJ>VJ;S2Apf zqa_Hag#iYHfm5T}*H)ZxN$T{(9yDMdY0fF~&se$6WLd5HW`uu~`j*r3{)(4uL-^Z9 zEhlil7+q-rlV4imG(C7~RS%A}2$hyos3fm(pSbj!$%txRY}Sz7F%DuRMIDxu?2wHy zeQfTG$?gD^EU5NYY>rws=Q&ksiYnisX}W{jkeAanT^p$r zxF3wIZTfLn+nqE~!bG*ko}01;+J*pGCk&Yu814k3#o8{dMW`{anRnj?-`uj>f;N!t zLCSL$xQ989PUz~*I>F@kWn@$94Mf3pm@%55^eRlHC_-&swos(FuqarmRT!~c%stPW zbSBM%sAAftxYNNDZ}_hVp1<#z^SABHtBtRPdA8Cb{kJl3y-&!w*N9{n=&X)Z?{TEg dy4}yF)xg7dx`P_y$0&YNKe0c|e&%);y}zo;=8*sZ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/unencode_component-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/unencode_component-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..03dab1e5cbc4c4be319a7c6fcc0bdcdbcd0b877d GIT binary patch literal 307 zcmZvXJ#WG=7=#(B5H%|*0}IMRkx=pcBBY?Ukvzaa!<4~t;y1;rV@LjI#lNpnhAtgX zy1VD@A-%xt{AOB!gT5WnUyZ0|a!T`g(5PD@khP{COcXwW1cp8~rjQi_x8Btgcq}@pkmd^|n=SuCY=f0Awn=tL z1*9;&^z4dUNd4(pXHC!ieF!sM9IAaRb*w>Ueh4A;gy!Tq<~K`=K3L8CZNUA9w=un0 kD&*hD#+PEhTCMMlA}eX0##d34?bEpXWNgpXtK!a)U#5j-HUIzs literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/unescape-c.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/unescape-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..3305f8dca9014c6a991cc472b71ca67c92df2206 GIT binary patch literal 287 zcmYL^J!``-7=$wv*VJ?iT{1LyNeiLT{Dy!-TZ4vVNS(=pkfqm+s4N+MwB+AcA<&Ko zchBA3?4SZW zA(zU0de%ETuyCnowr9eckf5G*sO=9Sq@B=`Jf-|{?l44WSU8Wk`3NqhmvfE$8yOm5 gCCbfW@qFp1ikg;r`jSK~9*VJohhb+NM8VHT%7Xl7#4H}XmbtVr&mYy3?Su*-)$-l2chAtf+ z+VXbqZ>LH6Fza=DYzq4&Jg2yi-5 zfPb=^tZtwfW2cp{FuO7K+rB?GGWOozRjzr~Yd0FhplqxQw{{2rji( nbB+8P85&_F%I#vYyfUhyre&VKN=GdoZ{7#%2CiQ<_n!O$tZ!yK literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/user%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/user%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..cd7a0f5781bc6829647a38e36d6fb4123a698970 GIT binary patch literal 421 zcmZXQ%}c{D7>9R|Shs^9!^=E`?xG@F&nZghv`}y&`#2Q|X`8NLY2K2g4F7x6O%e6@ ze(*f+`#bSAWVn2SoRFFNSa4fGkq*Ua;`dv_^*ti!IZpi1tSB@$hGmiyvRNkM<1|EZ zOa@JxNs$8?9YG7GcWpz6qqa3y)+2+cVcMG119J6y=Z$H$)vT#dc$T8Xzg=-_u&p@m z1UQGf0p%FD1nt_wU?-oT5Uu~A9wk$|7om6$!u}WTp%b$jrz@+4+TP)@1!}B*$BOUi zL9uo&SN!oE6r>-OLUQ-M6xo#hL@;f&nCPrKg9H)O!qSSf!Wj%LHPqC0K~X4a4$8Xo q4b8ZOeGmj`FY(W>zwI|2BD!!1d+sk+#QEhhpjXf}lXJ<82|fWHNQa65 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/user-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/user-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..68331d1eaa94aac5e492092fc3176d38afacfb9f GIT binary patch literal 385 zcmZXQ&1=Fy5XC)|HR`QM54DFSrBE-L^W+ly5eU>$te!#%n`C1aH#=c>gY>`eMhm5Q z9A@6{y*F3h4yKzIEC5#Od(CZ)WjYnZ#2a(NO>Hd#!)3CPyCq_ z`I7zhTy|P4bly8c5Md*1R&!Q5mdPrOO=kOVWLRYdD(jM(EawuBK@g;a#2-G+duep- X-sidKZitJUbNzSJ4U^B3858^fUzd6~ literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/userinfo%3d-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/userinfo%3d-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..6d7318eaaf15635f51975eb55d26afa96a8eb811 GIT binary patch literal 445 zcmZvYT}#6-6oz*pu{!WVhc^=p-Hn25y-pE2KMDmWvX84GA#Kw&EX^rN%JAQtI(3R( z=H&1^=Y0>n6&cJQASYz1-e%lZP^1HKnD{5H;aaE?ZV^F`apGT2i$Zf_SSC3kt9dfo zZ-gk0Nxx|`DRLmg9dO3_Zt#!yLq(3GQb?ZoLn*Qe+gCDawHWKHJBI`j)WXt=v%;ASEj85CcEwRB vX%5P|7=~tC!Zrwkw3qm2S3j?~?l94*Yu$4h-6PJ=cZEHJu9>`-%$VREXTy=I literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/Addressable/URI/userinfo-i.ri b/.gems/doc/addressable-2.3.6/ri/Addressable/URI/userinfo-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d114082e5bc3db3d7a5c1fe556cce7bccd3025c1 GIT binary patch literal 451 zcmZvY!Arw16vlUutZsO6c$rA37Zu!kPA{F)Lcod4?Np?sZMue~c_m31{`aO99iqp_ zd*APS-*@6|$z=TqIUx)6vEsIZBAJLG_0L+vwNND>f}UdPUoDD4b7NR0IU(CMz5Y1} zQ5=(T(`HiSK&Cxz#q_>y2yyJT=E{0x95qZ^lXyTbf8V?^&32kK6$(!i=Y6-SIR3`t z9O?#?L*NoLwv{m0+0QTv(T4i-CDfTv+_+6I!b}yoVa6Ol7e}?3b%HbXUCT2trjz#b*?0cpcXc*I4c~_ zq@{*BwOyAflxYsix_lvxMOt$Z)0$6rGYv~&!iisMr-HwUJ7BQb69E#u-mfPFOZTv zhr8aYL%q_hVacnhMggo=1j^8+;J*~=DfWre2D4?*@2Hpx~O(`?w?R)4;mmRJuF zF9XBOKKstRbKH$)6@Ue9H@q}H^l-(L(bSd5^N~*-=;E~~I0>%{k>0Z-@_xsa7P7ok zsf*ktL|ATwN!~fjMfs+awUV2})SoAEon*2!_5+=yypW#}>O`m;QHOR`aDLG8AWLmn zY3QkNNZ6f@o@a9lwu9WX4Fd4f5k-wy)WLz};sASD%bKDU>NR*0|A%inTJd;zgmsoA zemzLNZkO6L{EO->mU9w69bmWZuw%<#IJ;MmdUlCf!L+X3p+5DXS8dZmWOWq=m6C>M zhUfdVUn#L;hSv!R1F^Rvp`B%Cyq%D=(&+YIa#^b_brKxl!(+T5m1Nlbg}VY= zA1?cj6`m_B7p~pUO{4ogheE1D+>k4*zQdVNp;V%<_StppHDB5?FT?3L)q`f^MtlEQ zOReayAxEljj*%;(G!=Y@PFk_;LC*Sk$V;Q3U|8#B7V?n?+Op0WEo|KbJ*&--!jN*E zcBG;!YeAEwQI~RUFfYiqHR&{kq`Qti8y)0Mw;$oLd73W+z=!3tijYs8J;T?c0@#74 U@El&jKI|748&fAjzLFJTKlBT~6aWAK literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/cache.ri b/.gems/doc/addressable-2.3.6/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..6e2de726865f77099bab30aa0fb743c360ab787e GIT binary patch literal 4300 zcmbUlU2oeqa1VnU+p(Q5r%AhZt@e$feb}&}P!VidlLC5ZGqh=6f`OnV#%3#tDoG_x z^XGRblA@H@ZqT>8C zA{GhzhbB>8l)4jk4xgWNqG02-rg=hTaww&cou{4SDEMWW0zN$|HEMX;S*T!{1xII0 zo~Gh_nf#rW0mm#WQmUDg=pRkqu^0^iTmP8L3U23TH06nteM{4lITsh&{p4oKjtV9z zMEi^NIjfwa{fUs8)hSqL-wzAydqH(PJD{4*4biwI_2yMHm+Qx?Ty+dV;xnFxBdWFJ zlTtHvc`FK*=Whp@iDWck@<9OzlQ|~y?{7|4qM&t}(W2n_)TDa1DW`o=Kox8?k4ni= zAl!&ksuanXo{2kGs3 z?Hm@NxaPu!@ZJ>$7+p-p5OpKJS=h-+XhI8{;jNko>EZEThSgIO=2Ls8<~3B3@F}-? zb{c0X&p33-HC@dz@w#l~HFOQMAXLR1djm2x0@TLNTGxnVA)I@=SEx{a9Jd5$*mg%~ zHx#%Nxp$3DW;CCcsSz93$KpKqajY+@3y-{yjl^9ip|IX!nhVG|t<;6vvB@_%qmtvo zQlo`KIeE)1qT?SG8`OYmjT>+bNu|#6TC1S^IXAFj9EQ8U@R>eX}6=` z*4`e7LSc8=hZIu;V4r;~V6_?_R@p}_X|=Qt8QauW_UrzvT9 z;90<|ZSW>n)ue)1rb}tt;l8IkC9U)A1@;Uby|ND`@EC%6@}F^LU{%Mcv0C-B z2qTwMGZFzFL3!e+GNA;*u#k{mAKJcx{pA+Tz=g%6po^VjEJ4slaK)|}NOUuG;0WfC zP}{<7#}+M*_3L$|5+zRNvLDy~W z2@Y&S8Uu+*EIOXRM0CS$E#V5jwJwNp4pglqWno16uyOT;HNn+6aA0Zsy9TF{PP2N~ z4IOGN>z_)-K3TiEGpcN9cW00wb59RJ=Lo`H`Ou;Ec!THQ1(vz@tX&;Lw<4Y0emC|I zd}!~?n4DUx`W0*shIMxt#!-!1hTWQwkU9;9*RR}!xGIs zb>AX`wogNc+FW+MWAKroXEnL5*&aG+$-Rba{R*}R>lMp8Ra?5##e{?2QLmEXIOp5 z;c6z55*F*pCakK)_n7f_{ukN}AEDK-y76msxzgsla@o3$f-imLec@v>3U2glTWr_o zUW*HsN)-Im$W|D_GcF9D%_x3`F!>DMM(%s#W^cbJ*lj6%d-&>gbo3JIAcU5kLWy*) hRZmZIow6wSp8B5>kA8dn`{O?!9EiBYP2u*>@&A3SOJD#1 literal 0 HcmV?d00001 diff --git a/.gems/doc/addressable-2.3.6/ri/page-README_md.ri b/.gems/doc/addressable-2.3.6/ri/page-README_md.ri new file mode 100644 index 0000000000000000000000000000000000000000..ea840eb7483454917f71dbc8fe697f1242345d4f GIT binary patch literal 3157 zcmbtW-EP}96kfK$X_T%Q+O-9?0wd(2Ne0JqlK#rEle9@!1L-z6$mU*qcv$g$lry6=CyR@_Kew7;iK)C>J+b=19?XiBu>}*3VB(ZHHR1!iY zuh{dOG38Pm-rTdlOr3L^7eGBf>dx9mpbqp)_MC)M*)l)h@;nYgP$z&=y|mBlTa%t` z+Ar0w9F|(<$6wE^dqLA6WZjd^7c7LBc46JZk9E&$u2a(E&}o=GDP!BR=oq-l6KBw2 zybD!)SZ4FWy>*K=5z)&}*-B)O@$+Yd)DI-H9p-F`nDN&ki@Lz8E(^`(Q|6GZkVey3 z&saR*ezzyj;LcXaAMeO&t@dzvwYIWG#sFg?yS@vN7~gg)rfv_&YPFWq#b?k=1-vsU zAjXe&IgNX{jQ`FIhu=a-egrOj7L5*-U;-6$sD}!55o)5H%vvL~rb#Mn)Mn{cQ~PEUNX?E2chAYc)tiYIP3oJMZ15mF(6XXhi+ zO93bv+Ym$KLF5k3aY5D*6@C(`s97H(k)Bq#{iR&h@z2-^p!#s`a93{xfzV1r%)~_u zvZ!1nhKk!H*hN4`Dm(V-bF+2BFV*L<^tM5`+>a$DfzF)zXIYBO{8^|<;tN6vhd7`v zs5&QDNkn4u9kg4-592_uQU!y{R4ND62MFsJZOoGeL4>4{N4ZA=A0vwSMOu=Cj0154 zCLkCPmqiF03L+V4KYvEno;-e7$=@DT2>Kgp{o#X0HL|Fi2)VyhAu(qszG^K*Br#TE z%C6OJA?e7|6eS=>DnV4I6}Z-h4sgtlto7WUtejn6NbFdfau9<(|MXyYcV{1aoR5Iw zaQ0juROT(*n?;*|IuO)U-(qK~-X0cIwQW>yl*)d6wti#E_Rgg3es%@zP>kXAol~kJ zKoWszrs1aBGnTo7!3k%xF1k6x;Z5SB_GY0CS_$_}!@wtLkZGP(45xs_yt6`jrmmZq z%AO^$TYz8*cfm536i8KIcM8EMH=0DdnR>OygiO~880nS*O1G@@n3p8h@As?!y!-vH zUw{7lm)|tKj7@~8MFanBN~pX(eL=f+>OP_O-N!0n>}-H2w9{yL`Eg&=YHxdkHL4+- zhLYL7x~cM&N_$TA!ikuuy2v9Y(h%pB)qak(qZ8i)i8Dl0hyWnNJhjKIQk~8_?lO43 zWL!5&{Iu|=N}wuF<&n;3R{tW8?EELjdqayksS5z(o4-y6Ij38Vp#R=D4>#T{z+@J8px%J3eZHM*x=8*7&hj*>b{(4i`)(a;jmRef2Etl>s} z1&4KU@D9rz96xGvWE#3Krvs0*nrVoE;t`IMs=t8jwO~%#iG>IHCj#VBFAO{lpRy(g9(5 zh9dBQ$b?4(2VsOQ_XJ35`@6Hj0#4S9 zp0X~JZE$=VSqDxM$;8M^9S;37yX=rM`F@YQ$}NibM4)BWzjC>5fjN5bXhFqusU#TJ-{l(Ov+F{Wv?9h*G3T6bfulIjo#y(wKGZ$ewh&{CdX8 z770~3Sk8Ffy!Yn4itokM&(F3L;+u7?)Yn>ipI@jrn_qqE>lz(a8@ofJ{-BFQbhAk( z*?jiB_>Cn+Nwl%z&Deh{-LCJ1V6eVLL$R2popj{$$R?9GiTM<7|9^WYoqTYzYa%XB zv-#bNkw9{X9wbz#RjUXc^qn=Jj3;SGNmAB)1nWSS{Q?7)wxELsA)_26;4_`i#gV#|iA4A~itcKgm^K9=enV zhrVOyLD4%FQ6bAYKqnQi3HFL9jIz@pf*Z^OTe3sAd1T~US@Iu*_YF}eRx8&R2MmRF zEG$dgu0AXSf|#bY(wNO(YgMd@zGk{hR}7_fYIzac24%(gej7~Nk}NcCZM_W|8PabH zWTV%~be+uB`N{B2a?Z}Q3=s=Rd7Mwgtm_M{$~+3S*x-H?@NzD{J@1?)R*x0KO~h&E z)T1N}mu!AEMxw-L=;SmX2A<**FKI~YmlOsHweCG1BB_hI(VWuWYCO3l=L6hyVZp literal 0 HcmV?d00001 diff --git a/.gems/doc/buftok-0.2.0/ri/BufferedTokenizer/extract-i.ri b/.gems/doc/buftok-0.2.0/ri/BufferedTokenizer/extract-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..47ac9d39625d24f5af97b72be6937f82a3afbcf3 GIT binary patch literal 805 zcmZXSO>5jR5QcLoo84?qC4@pt8Qe<(sq0>y%jRPPhHfck)5{*r*dE8ivScJVsoV6w zcVs(-vKN77Ml;X*YF^FnmHfZXujbm=zHKg1;Uand+&h8dEe)oUPH#GQQ zu&rj7i`_g4HtTUTIIPJ6DnOG7rZGKOXM}nHU4l?;=b%7`Tv31_*BLcc8|;0_jM2EA zn~)1&5a9&b3uujg6a^LFDpmzg{y^0OKBADANdl)~QWyekD`BU0SIt0GY6FC}_nmUG zcB1k;tfjHg4IzXUog>!0D4a$V5bcs++dAz@xYp&<;zBhL^YuUJ5XF4C7ASnT-6*Y^YQ$Imb- zw5=4*+b~)SK>(ukesPR<0N4@aJl~1^|7UmNBjYz+Ktrg!Gd?EKIv`1Y9sJ|5j(5Vp z^%upOAg?-AhXdo$suYrv;I$Olr>rY^Y-q9}6|Hn5Tv`zp+}@_8(M{_7zooiNbFCZ? pv1vw9KSfcrJ4k}%XqA7ydczxiy0_6jm7k8g`PI84ZZGiM;&FTUMa(J4uq_ fERRRG%buEEh8E{1E%s17KQ{7;re*3$F>8}w7z~DC literal 0 HcmV?d00001 diff --git a/.gems/doc/buftok-0.2.0/ri/BufferedTokenizer/new-c.ri b/.gems/doc/buftok-0.2.0/ri/BufferedTokenizer/new-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..9bc4ec8843065db70065c83e8466419862f267b5 GIT binary patch literal 838 zcmZXS&rj4q6vsK3b%mQjJmBG_@c;>djmIIH71X2&Akp=-CY#sxwH*skkwKPoBM~X@oBpMBcHznA;EmFt~O0B&BbaX7KzEhLl$OG38IMNxE`}Zxx zDfx)O2=(R>DqFLGI~E`n46Q^(2x&i3OGnaxsuS?B@BwYmXymkDiKVv9w*IL1&c?1F zmjZBcN2O$O^egH_u;vle`0|?V_F>fSyw-;D?4{AgnP3;!Q&%K8HJh_+#HuB%#Kx~` z$K5JmVQ9tmN)U$Bc2$t!VK$pBck=Aj(Ze1&crQC}oP_4DzvS7$lTA#c@?hNI8+IL< JOM~9e{sM2z7-;|i literal 0 HcmV?d00001 diff --git a/.gems/doc/buftok-0.2.0/ri/cache.ri b/.gems/doc/buftok-0.2.0/ri/cache.ri new file mode 100644 index 0000000000000000000000000000000000000000..ee107e3746e887745805fd54620528d6994eeefe GIT binary patch literal 371 zcma)&F;BxV5QRG+Q$h;}iLO-HTSZLBY=}nk)Fn&|k>gxiQ|FBAGa&Nku>)g~*iL%y zeR}Usro$D#kf^|ub$(zXUp$7c0|#wo4}kg$9OG-L0bvBFhQzdL$j@;pa7kbA~Ce8rfeb<-DGZvi{l#{2bli) zIuFEadwu<#bA0?^^$*|q{ev>jPt|gUrl3WLsPVO3z;vZ_x`;Gd* z9{SFF$~USel_Dd)*F$EYZ<~s9OKeJ1W|eP*6=+k(Tg1P--uVR@ZZuSd*gjk$$s}*0*@9)9%y@sT3wD5Eeq+)Jd+XObnzF6Uvi}l(7ZYNs5vlJkN_)B6ob) eb#c@w?@#Su_z-q5%|7@2UbYV+XS8S}djA1rT)VIU literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/Equalizer/Methods/cdesc-Methods.ri b/.gems/doc/equalizer-0.0.9/ri/Equalizer/Methods/cdesc-Methods.ri new file mode 100644 index 0000000000000000000000000000000000000000..373e4f204cf5cae2480867d265e72eb8e23e0781 GIT binary patch literal 491 zcmZ`$&r8EF6z)ONx?c#QJIuorLh+dXPZE z%lE$Teeb=KXbt1%2gLv$m9D8=s0nzR2S7eAiJaKDh=sA{ea_ z1(R=uCDpH83*h9snm0Cre%exP4M7Tr5susoSATP#sHR&@+X{I&izlm!PnoJ6PZ-rq z>w^VX2zu#8NS?(PQWUrRXy!&2$fHTBYGLz=(^52BlW(-Db4v@!bG6BtYOJ$l@`6kC zp5R`B`w0p5CnRAO_n4%{cqI~%5c+LbNWmN)!l>2Ca%OqC4+pIlZ`5)hWbsfm#?prI zBNY$GUND@^{MSErJ@u6D<36d!-RX;SfZ zotb>!@0-cw^c`KgIm49Flk$B8D#vlO#HT`c242LmL!I+s==RTF8YcJ$NJ{NYy=mIM zb33GSRg(ywB3-vaBPO4lic+oG6i}*ZIu}$-sybRg+W$Rs%_Mu2tjZmKCUQde;1mlz z3q<8WFnNMhkyoyAg1R8TDj7-w21&g;n&F@9K(O-pf|oFX{%j{bAHW+cDgpMzAJ}`4 z2~)h7vK+hCd#_EoZM=5~*(8TYM9D^zNs=*9gVuI#X)n+~1ykO)*;<>J6(qVc86GUZ zarS$i$Ckn1}G(Z%<%7<1mSok(x3|Pg9y@-LE4Kgku zbe9EB_U+R29rt8nx?X?yhr0s>z>&xC@`Z(l^q0NS2=|-FGqJvT7FO8Tid9s|Y{p~oWjbB_?wJ&iU;+{>Rz+B*~cwxY!5@W%^2r_4)oa`u$|q1DX}O z5w_X_tA)Djs*TZ2W!YLnr8gDV%A(({T7%U0nKwJi<1&5!jP85~rbA^on^|>Q!y&j$LqzL(OQ5g*=HZ@ruA~}pv%<$oVqM;$hI%DqIb}}@gAsM&*S_+Pwh(!wS9a4Ni zWZD{SF@C6V=8#NUgXLIoKV^D?-QeVWSPMs#pEw|&4(BP2-KDd7Xt?4{TkQ*U(KvF9 z$75U8ZI8e=9`p-vgeM+9Y=vhHVV PsVCg`yVC79*n#{DF@En% literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_cmp_method-i.ri b/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_cmp_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..eeb6df8767918134ac834796f41ef3bc0b4b7804 GIT binary patch literal 458 zcmZXQK}*9x5QTe?v{oqyZ4vaaqzCn)Id2a}Z3_V{B6oKPnLX3-xGU zGWK3)^tjY~4HgwWYhFKrUR5Qf&ZjC++73MmOVHNDT}99TYo0;FLPNRq#)q*N`SVH5 zK|qp`W4R>_3`xLXMwBFWiG)jIL8f?N$Qne2hVab!@SHnMvLT}tZj9&P_U!Hj$kn3@ z+EU~0&hj+WXe%vAT*)S4_P#w1dw-gf5K2yVLAOiV4RbCq@&|$^H~7=hwNC175UPS( zwnWIdTo{&XRWJ*QK&En*Drp_BVF?QL83aMxiv0HFRqZ-(rT2bI-;UB@)7f0<0>py= GV}fsngOkw! literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_hash_method-i.ri b/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_hash_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b6ec3c6d4b1d519c42f6cd82c60836c757002b3a GIT binary patch literal 459 zcmZvY&r8EF9L0B#ZcZ5pn+ke}-9f!*&)KEwHYhj|(NmG|ZTsySmL@exC-bkjKc*sj z&3oUx&wD$)7dm{Js+iInxmlpiR1yw(H*k*N)nqP;nG-;F`gT;22r9RJgH)M$}3N_A>$Qpj8n1wNxKywSNB!Z zj+*qhiO0T1TWU$dQnnS7*ZSBW{CEz0C^*^ntVP=QQ!X%YM}kM!__fiMjvCeTRn9HT z5E3qzhNW8N%t9oPsg%V^+KSh(2!(q0JTL47ZujD{NgY+A557mQpW?%IvInJe5O)HM G@jd}u-;_}R literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_inspect_method-i.ri b/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_inspect_method-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..b0d4032fd005592a8ba432377623d3daed60822a GIT binary patch literal 464 zcmZutO-sW-5bZ(ITBRVgBI;p@f_l-Mx0k4GA<&A5o`NisWYR9(?8e3O z+7AIqww6d^iP!~LqOnx&ksFY#KvZam%InFoEyxrv3|ZpZc+T1%u{!~BIdyScYS`Th z9)%ihr6q|g*@VnqH^*V`hjS1@$;me62Bh6E=K>>tAb4_vUoBnhq(*~K72L7~LdNCX zuw1KxSx5vjm9tby>sm1^L80D*Ac$L$-@d%6RR^y2-goVrReIPo_MmhD;$DC;!6#7K Bmwo^M literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_methods-i.ri b/.gems/doc/equalizer-0.0.9/ri/Equalizer/define_methods-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..02ad3983676ffb593d3112e212b8d8edf9a1c130 GIT binary patch literal 422 zcmZWlO-sW-5bZ(ITBRViBB-#W7rkiC+e@r%Az(#BPeGPRGijD?cH{0wslVQQSy8X= z&AhL@-U}T*&D4t0Te)4LO;sEYc{gy6V@$Y2merVXs54&#?#2AA0Kq>|kN@x!=XpU7 zbIsquqM~Pw=o0j%$SExyiVUUg(E~pRZB5u$^!)eDBWPG_$Wv#sA3A~S&FTcirbzJH zmb7_D1O{WGBpGjTYn;;lpWsx0+}xKXI%?8yMNfT=w$PG;5=Y^fX d?OtBhuA_3(!EVzETAehjJSd%kxD#NE_XQ;shZ+C? literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/Equalizer/included-i.ri b/.gems/doc/equalizer-0.0.9/ri/Equalizer/included-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..614d48218e5051e75aba7bfb10f9f93d15ed61a0 GIT binary patch literal 535 zcmZXRO-sW-5QaTST5By7s~#%2#7jM>Id3oVqs4#~k?JLsFv(7urJLQj*;w?~oAguZ zb!T{09F= zZDyK(fk8#POV9}PtjH)WsYQy?)ajv{fi}6{RP_A+&MRn`YRD3+f8bl5-Fs4MMj{Xb z8JQ<2Nvc>Okno)R)$V}q1<2Vmm$;|;jTP*o(n3o7(Sk7{4D$#j18J->`cB{v)FBw2 z)|OeWO@eE^(j*d)uS0M-C7V7A>(A# z-h$C^V=mCMPXrHdaozWg4i{6$RVgiLufq_t9pyD7>(v)TAL5M=l9mnza gJiFc7o_w|NcgLRH+C;COqSNJ*roGPN`{uDbxD|)j-%KUMg7lnH9gEj4#@m_%T3rv2oQqVbC148Qtx0GB-U=Qqo zx854OftqGL14dQTo}WT6W%1ESqLZinTs4eXyOt^+GU@P1)z1%MQ*0o=uohRJZ&pod z)Y;v3-oI;)QcJ$G8uCtWeD&SGyn_^5hSu@}dJ0Lgm(EyG7Qazkexg6`_-M;@Hc3sx zzL119>$xjt)-;93Qc+=MMP;<_AL5FVlvyT8lJ8{ktM?zmNlw=4eS#9>pqBQ)uDmu*)Q`SZ4HC1SXB z=Dm3{@AbI4Im1mV87Q6RYU2^q4Aun|{2Ou)dqFs_5Olq3VLS%CN@L~Sdm%w5<1{V= z*aDwYt#iI8G^ouHK4*d|6(uG6pRS?L&8Dh^ukC1yMJ4@{=A16XR-w%z#pP0fPUQi( z0g|P$A&>$$0{8Z3;iz+KG)MS~OQo%`-3`XbA8+;spP*I@A6!DjlFSk9w6W~^E2>s| zz>NcpdeWda}(~S=PRX z#~SuCx&$?^5_CCun}k#HJPXO>rJLA|My>uz2EpV#D68f)cp8oahhkrIEr1{dzrWt; Ub$i{r_Aq5d0#Z}WQ)x$k0G9@=i2wiq literal 0 HcmV?d00001 diff --git a/.gems/doc/equalizer-0.0.9/ri/page-CONTRIBUTING_md.ri b/.gems/doc/equalizer-0.0.9/ri/page-CONTRIBUTING_md.ri new file mode 100644 index 0000000000000000000000000000000000000000..e8109e312a4608b4ba913a43b095bdfad6cfcf2d GIT binary patch literal 1521 zcmaJ>U2hvj6r~8+DHRe01QPIY{*o-Aa|?%drSJUg?@N8A*Cc9 z%TCS2?D@L-VoLp4`oLa@m(uT)+gm3Nf&546g+Rm9v5hC<$we=H44e6__d2sU8aceY&Bau@!8v@*E&ShUBsbh@#OOE`uh1AlXT=R zY(Dr8nw(xBHb;(;C7bir$!6xnmv48)Re#niEH zSdq5TQEc&BYHPIRQ|b-Nz@&7jQV3(P_pWyV=~XLj!-4iXwrD{m*Ulr?VM~&BpuO`u za+Y*l(z?}wj4r+O1K~47Z44$7OK%2JnK9RAice9i#z{(huA&}0oXJ-wBOy#n2-I>~@vOF8J#-v}4H-7Zz_exRdxeAmCdZRYx=&pA@X0ruH1*~De zid1@*JETn%)hX*m_v}MfI$5|7F2J`mW`J=xM5viUgjbOT-3?kuTeS!8f$7X(cJkz% z$zt;b{DHy7i z_XnNuko;2;TZxT95$+0V0bA<&hwwxNhz9~HaUe0Usliw!aXyXB-Wm;AP>+4SIcg|< zlPoQKwo0WJhqD{W>m~Ndmz8fPv~WT`QO^yIB{L7PCLTM+TXoR#f!D*KOz*^T62H4; z48Rq_`GAS;za_}Gq)TU0pdR-NEypWzy{_KKICjMIms!4;i}MQy9=7fDo`!AhUAK+- Usk*Wr1pcGofc%wGg1TP?TKnga=ju zuV0`M+F*mqEtfU&^%4n(0?oJvTOyiKTl>tlz@80oV^kqI!osGHiCagzm6b4XVN21& z&|%g$4lg^(jo=l?8bJjdui#nQQnePeFjmXLL3vnIRPE+f5j|E_axd+H&!KdA8)v6A zXv?YgV6QfE>wZP&wQ2K8n$qi4%{S5!<*mgA@dkYj1SfHDRwHJOSOM%598amx<&yQ7`AQ{#@P{n5rusP``y{us;W}Y&UT^djdWQU z-;s?!_M^r{3mI1OTzwUt-^0q)%A${MK;6hXX@_;_uT06&SbiK%c!(H9;XvHY(K05` z=EmaUNSs!qbf@C`C_cSWg$qd7oIsY$*nN-^pcyRF5zYyDakTOQlN`vLH7HHcPjd`&4Q%UIr0P(8d3J(!HlxlLC+97fMt*}I$cFU3d>cxOfrIE!oE3*lbFV{6gkO) z#OxDlKw==D@dL7X5JeqvutG~|r*@hwA5wZdXE0Bqkl^8j9MK{gOd@h1M#Ix6pbHPe zU=iFp$tfi0B1Kmxt@m>mC}t3&DhQ^GCh>9Y(Bd?SS&F9~CXlid!adE12SG|R7uGCI zki{jA9WKw<^~L1BV4)jIXXP|ItaO>KFp!h7kOUDz;vnNU#oZeCKaSnoAHVlUV}%c5 gT?+2ru32xj+OI9oE3sDFHSV;fB0`G3KPg=XT z&znD;oHd;&D7b}Y$NxS9y`oZqblo#5hk+Qy!kuoIg*0(pq)H=*^-cFyJ)u&o?l*1s zyX^1`^E1$Z#eI8=xZ4`uX*3FNQ_9&NAPdz(N4WQv&!KTTkTeMk)tlWyYxnp} z1Stoi1qqYbeIPUr2#Zw$zGfmO5$I3^%9^O|Ou4p>wkDJ35RuTlF^u+Hj{6$d4~WY}j84So{SxA-*0LwD zpg`i*29yC|bs#a*%of+)0+!<<_^B^;>hmp9Ba7wvDzai$mCU!42o~!eMPTk-tnQ-& zQrVyGdmq^MH|$sJ`I!M{TEs@`eNuZ$cJKd~vpAPoJ0f$PwaU}ooWdH(#CnEf`mt16 zrZBe?QWcWg9P8Ns*J1FMKiiw~?O)Ai`^75Ivh^ufutA+aBg4Nr;MC8VoVh$dCodzM z;d1)?WqqqS?7B07Gi1)L$#Zw7-WL*U+ub&OE}!=I+G&yqsUaZexHapbD-HI>pPi5? z!WlL)IVO}v$~113oy~f*A`=bR-vUAh6oai7edPK!M|23JFE|$?94uBwiJ4L~qsW$) zaD&hPA;ageRp@(rkjDcaIc6MPCejdQ_NyMMLxF< zIC364KV;+Ot77%*D=<%-%12-xeE?H&%1-%8%gO5!f73bsefX zv2WIlarh*XDQr*y_LJG1#4$M4YOgy0Y*rYaSYX>98>F=Gqkq(iF7^1C|Z_YmUJ zBDNmRrlCdSJIWPwrqucp)k#nZ2AX+zr8Az)+=@C%3DrI(14b3);s^!wdmno==7mGh zeZIt8^eHDysT6VMG$rQx$^4YlRkI~{hXKLSX@h0>Ou89IyupJKI8cR?b{6X_s))8F zFijH#o7k5EDUt*N8`XSM+-XRY|I;S;MX`FP`epTQcY9+E9-Yvb{EBxzvNy4}utnd? z?n{gN*~R{q#s2se6IznC;4wM_sg!-%$dzqfLsqeubw%2K$Yg?Kk@sdJ6RuxFQ)@~# zBxlSIDRA}hrH8qQ!uo*A8|kvGj4|)eI}H(Q$-Go!LM)g6<2C@9G+w^woVSi&cUmu= z8t}PX7IyRLbQi4=d%PM`RW-hZy6htw!@j vySZio2TPxEs2AOGT|`Xx!t9ri>h-0FdYWRY_e8(v(vvr#~&GOcFQMSqKEo}GH+D7u)$i)ESQnw)+!?zw&4 z7(zUK)5Cx%8JC7zbTrmQk`^hANLIE|K{dNjvYxlx@`iuReJ}`i4n6C<0CP?;6C^He z9T)M6a@eaEzd)G7Myo{Xk5o%!5iz10{^#P#8E(O!OHf7836m+Is8+-+Len*a8m61 q7}0pWyVP~q*gF#P?5#^Z&{RhG?nXcRi_1wl5!3I}uC%#>EvQfFN2ZJb literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/certificate_store-i.ri b/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/certificate_store-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fd6d7f479fc1ddc3d0d4db01faad162bf0bf367d GIT binary patch literal 291 zcmZXPJx{|h5QaOTv?60G7}$c4=m5!lU4ld-GNeL$Oc^Z4xeyCGXW18_{(D??LM%6& z?tPzoE>@qgd3z=W@H8D8k;w33V>FnLTM*;jRTx3@3M?md`S$!fg) zf457j3Q{+BMk|7wbA2QI_v`>7YqmJ?3ewU^&!JtwWjSbrb@pI%mk-j*ULNx}9HYB&%7BD0@A91u=NCf@Nn=&>$2|95F$3Xy~UXigr0yKb literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/host-i.ri b/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/host-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5ae0a8ed555e81304b4956032c271df78ca819a3 GIT binary patch literal 265 zcmY+8F;BxV5QRG+w~&!aAhCso4iL}RB}gdQFPkk59hpH)cNvZb9ybaq<;NhJ>4sH Pb9UWhaMCu|&sOtaRz6n9 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/ssl_handshake_completed-i.ri b/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/ssl_handshake_completed-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..dba5a70a8bc15563503ab174d0b29f16d47855ba GIT binary patch literal 303 zcmZ|KJx{|h5C-55D6PmyB?g$n0z#0?*Cj|aB0~`3W6EIJ@daD8W6Qn>_21*D69dZ) zr#n6Gd$#$4?fbJE0G_5}hoqeBw|dalf}OME)b1 zH%^1P`R{s{H4Wr`7Df*au1-|P!(sLS$(=1uw1K?#JW%Xca9)qvU|T#GEy|GxF8Q%c z!xM%QEmKKli{=;iF^FuJeL__`tBEP(QcvHJjlo$)To`0-OyMU=Ok@I$`>Cp`U$w>h d_HKEt^VH_zZ=1AlhRajdR~IZdos+Y{>KF0|W?BFM literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/ssl_verify_peer-i.ri b/.gems/doc/faraday-0.9.0/ri/EmHttpSslPatch/ssl_verify_peer-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..f63e43f6fc639cd569542159564b3bd8a824ddda GIT binary patch literal 298 zcmZ9HJ5R(g5QMKl;Y2!!L_wEppn$mEYl6f@qzF3ks8U#tvmq9CY}p%7{ymPaf@X@< z%zQg%+YiWIpR5FUoR$V@w0)bY^E%H$(EJ;{8W!#leFDj$s`K5!JQKOMppSy&xcl$g zCshThn>($fg_~1#BmCFw03v5LIMEi;(g{zY-M~dTD2;V~uT@tJ!i!!kMHENq3p9L; zG`>>Y%6sr#vQOTDmDVWYBZ^*4pMekF8cw3q$nC(TohV`g?@-$x##pU??saEz8& YQn)%-Nc*b0KK;74-f-R6e$q()0oSQr8UO$Q literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/EventMachine/cdesc-EventMachine.ri b/.gems/doc/faraday-0.9.0/ri/EventMachine/cdesc-EventMachine.ri new file mode 100644 index 0000000000000000000000000000000000000000..7332911ecb6aeb12f81c12a9818b473aaed52c78 GIT binary patch literal 398 zcmZ`#J5R$f5YB)S(+3jjz`<7HDRBi3CN8L>Qo*JXnr%Ar_8p*-oMV9;c-vI_Z;6 z-{T$^Xoqj!pN+uy&A5T9+O(qrx{|2MuQz+pq2{8O8d98YUdpU6`1Yi)x%(O|#?d?u zQHSunwA=+x6Fe(Bsi43`X$Bcs54@H7)3eT*fd$?uV5Vcj=n##bHK5FQL6c);G^_HN zP~7{Jq+5z;hUa!{loXNA@RfBYfC$hY+l6&<&jUu7dCeR29o)834%s=2m^vCgY^B$dBFvWed%2^eK+bc>&n+cSEjr|QjTw$h5Dwtny@#*>bZGD*+%bhu zdD}v{tb>xHh5L=#q5D~5Fe+9pOemmi7IeY)8QeCLRDzPDl0!9Zjw*_hq7s_TQSt1C z2>yb)v04T;3*^#VJe!==Ea0F7vlAPw2@&quAe8;BYf7@z>N84q50B|=%J|6L|J*cn QJZu9$tkbAo6?$L)0R-YzcmMzZ literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/cdesc-Manager.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/cdesc-Manager.ri new file mode 100644 index 0000000000000000000000000000000000000000..86fb211031c5616b1c70c7eb4160740ed6f50ead GIT binary patch literal 768 zcma)4O>fjN5ZwdHM*GnNMO-Mz3KGX|&dz~U?XJjS0YQ7pA#$8aV%D*Z?QG%SGu{ss zgpiOA)_7*#n|XfE;s^Tj%bn(we$;kg@>VkE%1aR!$zsbC>%c}dT5pQv-G*7#u%DFP zG|YIgl&-fQyf>7d3$qC8=AY_szH`Z4iI#fw?aaZ zyp^I}wMR`>C`^!K1w+-NB-ge+)TX%}gs*yFjZmGdTC0c3vsyx>+lp)DaY|R!AoXLK z&C+b1mXpJohLvYL{6;`3Q35(QV=VF ziexDiDyKM{xw1t$Kd`W-!M9ERCPbIK2fnLXp@i$U-Gn^n| zJF2H>iIGBO-k+bcWf&;CIA{<(oc(hfl=|T*{fZk1t;$$T(vx#0C*7j_d6B&Smq`Nw I|J&)m09^~}cK`qY literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/check_finished-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/check_finished-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..537a2da2e37ec2412e00fd5a2a20ce8c964355c5 GIT binary patch literal 286 zcmZ9{F;BxV5Cz~4D6I$^6$@Lsz(TyRT$doIMTRgSm@-%w`_fo-?8tV6`tNZSCf3uv z``%q`zG3_M<|M$2JvS5wr`oMv*Tt zlmEcs^l1lxcXMq-nC;jdgabG>Um+|24H`VBL!#fZ zx`kp{dnE@851Y0@_q#?iHdZZ6$f2kfbisE!xUD9s1S5}1_T{ui%2-N`QfNNM#;fb2 zxCL5SEd!qgj?$bxpPbb^V6OzX6CbPzQSNy!l)X?&yB#C@r|0xq6*VJw|4Y-z;eMO; MZJkE-q0oE!2hE99QUCw| literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/perform_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/perform_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..276bfb5d1ed928d185361d0fa35c9c7f09763dca GIT binary patch literal 294 zcmZ9HF;BxV5Joegv?7dA7dCf+g=Fe*U4ozy9>P$;l)<_rm&U@5gY5|Q-{UAuY^T$` zd*64n{e<-VYFdEj@mi4|OjoCJ!&y3!?TyvK()Ucx#}J=N&JHD7?C=`yJDfaOfK&D6 z{RB|qh!?W^|KKq$OGu`INK}PWc}*P zf^^Ykq{R?)PqvAV@dxCE(b9{7u#@A(iQXD5JT{7i=|yWsAD%nWkTO4c&RMijb;Q}` c;c*#@B$T@QiyjtbyITXkhwi9e6grpx0{y&T1ONa4 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/reset-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/reset-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..d67ba026e11fae8f177dd1d06c630850891535c1 GIT binary patch literal 268 zcmXYszfZ$35QRISv}zcuE^O%n5+a_jOAyo|Ll_WD8LV@1X{`E3WIICr?{O8@)A!!@ z?r!q~yRUcG0leC4LveI{yHo4B*m?>SGssT7E}l7h?D3kY9;Zki;M9D?H~}4+b(552#F!*6 zUS`Ma8(8Ixiee<}l|2VBcxOaJsY$p&bk4?99)u+Aei>u!sxH=#Pq%25rzh_Jr=|n% P_RF+S=MCyNjUli<5lB{= literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/run-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/run-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..bf092579fafe125ef2f0dfb785cfc58c24c2a9d7 GIT binary patch literal 264 zcmXYsy-&k15Jx+pG$M=@3tPGX1Mz$;soF+l2m^vCgLO`v#;QLe`y$l;9!Ft+_ulXB z(jVA;om>ZSu(w9i==yf2wsoHR*(Q*jt2%$J&|{Cc$n-do^Z@7PgJ=S1(Beh<{Q|!y zRR!5J3#~c_Pph>-f1M*36SI+)Qpm~)J%x4y_vN6ptnQN%}yy|S0U2k#6g6k2jO@XlF^^1y}E?w2vvZt8sd{IZ;uS$yH)f9Nu@dt9e| MI&V-PHHN_c0ChA}`Tzg` literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/running%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Manager/running%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c8a02744c67535d4d6d509ea15e5331e0a1c0c32 GIT binary patch literal 274 zcmX|+Jx{|h6h%8!Zbe|LSh}SPEX4EcK&n!U4C#Pi%3wVwPGjMZ$aaMK?{O8x`gHF- z=PlP?u=#j%Ex^HEYZ(XEH5;|6@&`XztL){K06DQLFBp34@S1`hj!}AmQ~e&}2vDQN zi}bty#-1<+**FQUS_j*CzefK(rF4Q#M%uWBtQ^tD&@AAt?3I>PzSBw+{R}D+?Zzpj z;X~rQctQ5$6KLs-ihPjRCB49V?+lM9wB)Ymt+O$W2QH*`Ka|pDQRS5jR5Zyzt-TgW=ABBWmT*$HO^XTG|W~mRGK+>FaFtR;PL}bgASuS7V!y8(^@Lb;_pfp zt9r}7A`wr&!X|$t`X8nUSnvmuR5#M)k0>hHKG?iAy2+g=6z00lOWisWv3Y??KPT)< z!lntIyni7Nvv^u6VXbH45f5S3^@Wlp;UO$LqaBtGtM}u)GxDEs=nq-Ekgav1EpcdN zGrsh|DM{Ayp*Kk4O=r+rN{gx}t53YgQyh&HWZ~u2H>a^jjz`4m@(JAtecgks8t+fW zdnX&z{a%m9T6!TF^huHJv2ST8(Y(;rp8TP~zdc&_q4;P3^lmqHj@jI&#TN9R@Zf&f nflEJ?7YA^+73YzhB*XM~GYZm07N7rbxxCNvWPe33{T$x_C0*8E literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_compression-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_compression-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5bc562eb92d5375f195871b3521200c550c16897 GIT binary patch literal 313 zcmZvXF;BxV5QRISP?2s_LV^XQ3rL7$zA^-fMq~&`6-*f{JGnF#w$HL1Q2#xy!pM5M z_rCX?Ek9wsf1wWG*&G`TBlYcCp4ZuRM`njL=6Xl5O$%TspE-i)P*&+f$sO_G literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_socket-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_socket-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a147baee1fb63012474dd7aaa6cadb3cae5e903f GIT binary patch literal 303 zcmZXPF-yci5QVRhco;iRENmp#D2PcX%rz0bV2UV+Rw~;D(Ut zS(pav(U;;N`rvzVO|*%=Aj@gcEP9km+ubBOM}uJ57!=fru!TeUBpNjIn`K$OD3hyu inx{VAq5XL{*5q;cc6oXbf}*{dXTFmgq^U@GgV`VU4P`z6 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_ssl-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_ssl-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..c780840c78eac69e13bb899af2e7d5abae8790d8 GIT binary patch literal 297 zcmY+9zfZ$35QRISP?1hhiGc;B3rL7$V7e|rq81qfQUy~6%T6whh2x9-1JwT>S7Bj2 zz4yNF&X%9B-oH=_@NAAX`hmJ;tJM0xrs4X{@r1Rx
    zorOVspJ6h*VBva36q hJs)n-eBYmD$}~Q<`qPgG)?Uw=Z)8WIYwCi=;ukZfV#)vj literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_timeout-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/configure_timeout-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..aeeab9436b48564bc58c51c95c5980a64d169379 GIT binary patch literal 305 zcmZXPF-yci5QVRhc$n)vw6Kv}qaY@w%rz0bV2UUlTBTSv$>g%QyAw9E%Kdxyh@I_& z?|tu`Ek9wsf1wuO*&Zw8fx3FF&dcPgCEKfmcPLmHB+n5+o&iY9(|)#OK>wAE9t&`z=GZzw7i5kAEo1|Ucg1(D~)Bc(W*)N z*_a0HNtmJ$Ll8c?CfY_HkmY0)iveY)>|qkUBO_Qg8U^(tjNwo|i3TnQ!Eb)D?AJWA+OTvt~R1 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/connection_config-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/connection_config-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e25cf175f3062fabf4cb724732392451d8377b7a GIT binary patch literal 296 zcmZXPF;BxV5Jo$ov}!t5FtDWyEF>ekEt0R@p(THt!c> z9<{SDN5h9GeDG~@Og^9}$*8~w6rHl?k@ubq52Dq`sh`7#_?6mt!9v4jBEa_g!8=-6JCXK}}B)Vdi literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/read_body-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/read_body-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5f3088a48e31cf21a074ee64dd5e4766f799aae3 GIT binary patch literal 280 zcmYL^u}j1-6vl6mcwEKlz`?Dz=wdU!TPk?L4pk7HI)tQ2Z7|6TX{z+UH%A56$M=1| z-@Dj;!2azCdw@s3v^tHby1lt<%Im0w;u6(DfSg!UQYNBMV#!G*Ledf7)IO&a0A52f z=%>Sf`sXsDp@U>Nc>e2V-?p9;}hou#&2bJA*3i z_?STtQIaEh2U?>uiH}*(_|J(C5gkuLTFr6bJ^GZ#CoZ+cA4+MrY0BN5_TTsCc3tFO WuKtYkf%P}5-3vx1Y>R5Pn*IXff?Lf1 literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/request_config-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/request_config-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..e28d64aa962a74eb0acbfef6b8e0bb3c544c9dde GIT binary patch literal 290 zcmZ9Hu};G<5I{SiP&I5+Vqi-bSV$I@>k=dyks(wp*LY{-qff80JQ3W$eEShjOLVM~3OJz}zp36BLAB93oKUtR5t1{W#q5Hm{ a={yb(UHxT;LDAeSb+6=mX)9_ci`g%cB49xP literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/request_options-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/Options/request_options-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a738e169f52faaf8550ff0ace1eb4259879aaef1 GIT binary patch literal 292 zcmZ9HF;BxV5QRISv}zb5F|efzEF@Eh>k=dyks%;eFlDfu_(CjfUvMs<{(D@7iS_ip z_r1H?yhCz&q7LBEoonQQRFmj+l_nm)W}H~i$eP>~L3AvubYDs@l{|;Mk|U!BIM&b1 zBf#qt-2Dd+QCUJf&aKfM!R=zJrT?4*6x6dt#~X-?QF@-56>N)M8?4fu(QVc*zAQ*D zx(uxtg6_e$(II++ydbMt3@DX$ACu@kS;4Y3D5w`5IS%EMXwlG5p6AV~O1F3DzV9z| Z5r>bi|8|E%+1)JbUdUT%YErYo{1?XaVQ&Bc literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/call-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/call-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..5dfab402d5d35f620483db97b3910bfa224cb70b GIT binary patch literal 259 zcmXBOF;BxV5Cz~4$dqQSy0EzmEX4D534%s=2m@-T4A$9k8VftN90$~Yk4wgr-hJ=g zt=(Pt1vk3XP7IlTiIN=130UQw zNn+60nej4-K6)n-N~?wMh4N#{_#~vZ{+BVG9|J_FWYxPK#x0zH7Bx#(nze K(7sumCiVxFnr#Y9`Y%8?QDWL$C==R_ii*yXKDX_#>qs zcH9PVl%DWBLHPCGaDrt+=SS`hcXyqo6otALbV%vAu-pY-B_{vh(egW~_XOQ>r9hp>apcHw`8&HXJGhEMWxn0!9 zuofqq3usw`SzfvAp?6uBRtDAp-=UaiwKFXXe5-(&nhB!=Zq>6bDD$w)N6UP?tOocb zF^I`$8>G=bGM&;J_TcExE9cJ=aXt2f#(7f?K#TqB{*jsYr%UY zKi8+d?E7==l?8`~)3VcHo{@QvcnlKbd(!a2ap{2_#QL%PB3jL-_{L0c`&)V)bN?AA b{f2wPgsW5zmgj^Ir;rr0e_VF)^gsFqZHfuk literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/error_message-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/error_message-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..a55b3762f20146747d547d5f8eef091a9673e183 GIT binary patch literal 280 zcmY+3w%M>u=b8zH~@*dBWKynmSwioEI!%IweI0bS5$ND3L zY4<;UNQ8iNnw8Nl!{Y+f=ziu2AZoLvF{~jiCv?F#E4V9rZK%q2MytGEkUUCPBPT0| zXuLR;9Fi|6O13)4fw0r#*~{Lsl>wC@$-QiO46)oxMTUQiqG(oCws~rej@##JL7B!+ V(&g?ri}qo;@5Iicc{AvJ@dsXiTmt|A literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/parallel%3f-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/parallel%3f-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..15cd9d1ab18d9c0cf9f0b10454bb3de07a8ec716 GIT binary patch literal 269 zcmYL^y-&k16vR6qw`!zL6$@KB01NT_IuHc4$PfkuQwGaU9AfeOA=?4AidI zz1n_2_5R{UfG2zIG0kooDs|n}mB%1mFf8Erf-x0P9BEfSP#*Zi&pAJFpD+L%``48G z{(t^ZPzt4AgjS=2+ZE|~_*y(b78ipyZJ}&E4=D~C*tJq=?CQN%qLC}pWb2|dXxN;U z#~_MBaRSmhqY|5uPs)BqCWA99aiNhp$wp^WJ|3As?S2U%!=|fucW8g^FWYUIi literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/perform_single_request-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/perform_single_request-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..fd4f9865edebcc6d2cc7c508ff51235671a4a95f GIT binary patch literal 381 zcmZ{gF;BxV5QQ0#DXqj*v6LZ77g%TpSguPDZPW~<2$d;=bWG@k1t@sKqhV zYGDZ-z8)rIBq6}l0h6fylmpw00neQY?inBZ(-=hAy bJGIlRu+n7MB-~kbJ?OlINrie=!u#Y0spEf! literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/raise_error-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/raise_error-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..4814dcd93ed3540d928d8e7a66305cf160d90d8c GIT binary patch literal 273 zcmYk1F;BxV6ofkEQe~BMiA^-pY literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/setup_parallel_manager-c.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMHttp/setup_parallel_manager-c.ri new file mode 100644 index 0000000000000000000000000000000000000000..4101c597f3de855ecd9684398962250df20a2db4 GIT binary patch literal 306 zcmZ{fJx{|x5JXcT6XDjPNfVg{8tjHp>lCr+w1tmed%s3lz-1ft|@n= zH*e-<{SDdIhwTC0%;i8l*`dwkZIf>T@$7^{k4lje8V#PwCy?yxCV#2pf51z`26Rjw zV1M{zb^!lyyQDrr>gG<#-oj>a9?<{Hk%`>y ztF0g{rf7TiU9w9~P*zq;78Bth%{hqCTP+wnMZ%7vw}xYQ5FIJ|Tb5odt(l{+$hQzz>@0XfK>oux(g&~xGotS1D literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/add-i.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/add-i.ri new file mode 100644 index 0000000000000000000000000000000000000000..68d51bac0e27d685337aeffd0ae8d36c549dd21d GIT binary patch literal 465 zcmZ9JF;BxV5QP~~D0E<{SU|`M0s*R;YzQ-u3L23i2$eEraP0WfggSAs9ijevoTLn} zS@+KG-gmb@`oNRrv&=A_*V`COA$c+>46I7wLP3R1{B7N_ zBF6Z|m}WV+q)4()$jq$M@llYM0wVWbl+4QqV9!!_ydG3U|MGe^agR%?fp?}@@8Acr zDh(-s^0HoQk}FveLzw^~bCSv0SY%BY2>I>%ezF(2m)E=GQ&jc4pQ2lfpr`1H37Ktf cI^*Ej-eB@?$yNxnlVN4AQdLwu397aK15&J;7ytkO literal 0 HcmV?d00001 diff --git a/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/cdesc-ParallelManager.ri b/.gems/doc/faraday-0.9.0/ri/Faraday/Adapter/EMSynchrony/ParallelManager/cdesc-ParallelManager.ri new file mode 100644 index 0000000000000000000000000000000000000000..65f8ac4767d263fe8b0711d2a90fbf9f1435bb97 GIT binary patch literal 604 zcmbV~F;BxV5QRIS#58Re5DQz_NhBuDOHe6Nh618=@(?+R(;6H*I1bQ%kDZVOBnITk zcfR-CyYms+!r9ZUDgf@4uBliG+P36`qcl8yq?!uB#F|RFW7-36b(e-$cQ#zo1Hes5 z8^bifYP~tgVy~67(Vtb=vqix}{=y35VeeVN`2bu~{n|AEmfqD&8U#VoP;FY`DeNPR z$ONWI#RW^lYr*rV8o-gIJ8s14tR1Y>|9ojV%DiK@BD_KcQX?%J%G6-pY5ZnK;T^%3La7*As|>5otRG@KT0AWn%O;zQ7Mx!{G(`><%VGS(C;`|GUH z{GA%+E@?RDvNco|Y%IkA=>-ujOB=H@`L`#hk8~%UOmabdJabGu9{{t4>B{bM%vuj` u9qU{p?)8Lt+i?R+=l;_GY^)8gBtd)Dp=*C$f~Jm@Va*O)4w%25_fIA_Jb2xbc4Ih8I<&6OnSranGrP+x zi(SLwlbmJ29Y?8W%LNDc#pi3~;yt;MSlx$Axb;!ZBx-RBol7&;_RX~GvnuYf%H@xNt)YQCpU?^SZZwFPi zMl1Y%#j%tibFTOf%+0X53euF$dS6OWX?itAI*79Vj=Yv!v(7*&@*N`mbg% z-5K7u!RoBQKI@HF1Y?MSFAvsPq7}iH2eKEgCEImQ>910`mriW&$R0g