[
  {
    "path": ".gitignore",
    "content": "build\n.gradle\n*.iml\n.idea\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2019 Tomasz Nurkiewicz\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Source code of examples from _Reactive Programming with RxJava_\n\nBook is available on [O'Reilly](http://shop.oreilly.com/product/0636920042228.do) and [Amazon](http://amzn.to/2gJ6Vhx).\n\nIf you find any example incomplete or broken, please [submit a PR](https://github.com/nurkiewicz/rxjava-book-examples/pulls) or [create an issue](https://github.com/nurkiewicz/rxjava-book-examples/issues/new).\n\n* [Chapter 1](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch1)\n* [Chapter 2](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch2)\n* [Chapter 3](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch3)\n* [Chapter 4](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch4)\n* [Chapter 5](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch5)\n* [Chapter 6](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch6)\n* [Chapter 7](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch7)\n* [Chapter 8](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch8)\n* [Chapter 9](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/ch9)\n* [Appendix 1](https://github.com/nurkiewicz/rxjava-book-examples/tree/master/src/test/java/com/oreilly/rxjava/appendix1)\n\n# Remarks\n\n1. Some examples were slightly modified to support newer versions of dependent libraries\n2. Java projects can't simply import Android `.aar` libraries. Therefore parts of [RxAndroid](https://github.com/ReactiveX/RxAndroid) and [RxBinding](https://github.com/JakeWharton/RxBinding) source code were copied directly.\n"
  },
  {
    "path": "build.gradle",
    "content": "apply plugin: 'java'\n\nsourceCompatibility = 1.8\ntargetCompatibility = 1.8\n\nrepositories {\n    mavenCentral()\n}\n\n\ndependencies {\n    testCompile 'io.reactivex:rxjava:1.2.2'\n    testCompile 'io.reactivex:rxnetty-http:0.5.2-rc.4'\n    testCompile 'com.netflix.hystrix:hystrix-core:1.5.8'\n    testCompile 'com.netflix.hystrix:hystrix-metrics-event-stream:1.5.8'\n\n    testCompile 'com.google.guava:guava:18.0'\n    testCompile 'org.apache.commons:commons-collections4:4.1'\n    testCompile 'org.apache.commons:commons-lang3:3.5'\n    testCompile 'commons-dbutils:commons-dbutils:1.6'\n    testCompile 'commons-io:commons-io:2.5'\n    testCompile 'commons-dbutils:commons-dbutils:1.6'\n\n    testCompile 'ch.qos.logback:logback-classic:1.1.7'\n    testCompile 'org.slf4j:slf4j-api:1.7.21'\n    testCompile 'io.dropwizard:dropwizard-metrics:1.0.3'\n\n    testCompile 'org.springframework:spring-context:4.3.4.RELEASE'\n    testCompile 'org.springframework:spring-jms:4.3.4.RELEASE'\n    testCompile 'org.springframework:spring-jdbc:4.3.4.RELEASE'\n\n    testCompile 'com.google.android:android:4.1.1.4'\n//    testCompile 'com.jakewharton.rxbinding:rxbinding:0.4.0'\n\n    testCompile 'org.postgresql:postgresql:9.4-1206-jdbc42'\n    testCompile 'org.twitter4j:twitter4j-stream:4.0.5'\n    testCompile 'com.ning:async-http-client:1.9.40'\n\n    testCompile 'javax.jms:jms-api:1.1-rev-1'\n    testCompile 'org.apache.activemq:activemq-client:5.14.1'\n    testCompile 'org.eclipse.jetty:jetty-servlet:9.4.0.RC2'\n\n    testCompile 'com.couchbase.client:java-client:2.3.5'\n    testCompile 'org.mongodb:mongodb-driver-rx:1.2.0'\n\n    testCompile 'org.apache.camel:camel-rx:2.17.3'\n    testCompile 'org.apache.camel:camel-kafka:2.17.3'\n    testCompile 'org.apache.activemq:activemq-camel:5.14.0'\n    testCompile 'org.apache.activemq:activemq-client:5.14.0'\n\n    testCompile 'com.squareup.retrofit2:adapter-rxjava:2.0.1'\n    testCompile 'com.squareup.retrofit2:converter-jackson:2.0.1'\n\n    testCompile 'junit:junit:4.12'\n    testCompile 'org.assertj:assertj-core:3.5.2'\n    testCompile 'org.mockito:mockito-core:2.2.15'\n}\n\ntask wrapper(type: Wrapper) {\n    gradleVersion = '3.1'\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Sat Nov 19 14:44:58 CET 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.1-all.zip\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [[ \"$(uname)\" == \"Darwin\" ]] && [[ \"$HOME\" == \"$PWD\" ]]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/appendix1/ClientConnection.java",
    "content": "package com.oreilly.rxjava.appendix1;\n\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.Socket;\n\nclass ClientConnection implements Runnable {\n\n    public static final byte[] RESPONSE = (\n            \"HTTP/1.1 200 OK\\r\\n\" +\n            \"Content-length: 2\\r\\n\" +\n            \"\\r\\n\" +\n            \"OK\").getBytes();\n\n    public static final byte[] SERVICE_UNAVAILABLE = (\n            \"HTTP/1.1 503 Service unavailable\\r\\n\").getBytes();\n\n    private final Socket client;\n\n    ClientConnection(Socket client) {\n        this.client = client;\n    }\n\n    public void run() {\n        try {\n            while (!Thread.currentThread().isInterrupted()) {\n                readFullRequest();\n                client.getOutputStream().write(RESPONSE);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            IOUtils.closeQuietly(client);\n        }\n    }\n\n    private void readFullRequest() throws IOException {\n        BufferedReader reader = new BufferedReader(\n                new InputStreamReader(client.getInputStream()));\n        String line = reader.readLine();\n        while (line != null && !line.isEmpty()) {\n            line = reader.readLine();\n        }\n    }\n\n    public void serviceUnavailable() {\n        try {\n            client.getOutputStream().write(SERVICE_UNAVAILABLE);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/appendix1/HttpServer.java",
    "content": "package com.oreilly.rxjava.appendix1;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\nabstract class HttpServer  {\n\n    void run(int port) throws IOException {\n        final ServerSocket serverSocket = new ServerSocket(port, 100);\n        while (!Thread.currentThread().isInterrupted()) {\n            final Socket client = serverSocket.accept();\n            handle(new ClientConnection(client));\n        }\n    }\n\n    abstract void handle(ClientConnection clientConnection);\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/appendix1/SingleThread.java",
    "content": "package com.oreilly.rxjava.appendix1;\n\npublic class SingleThread extends HttpServer {\n\n    public static void main(String[] args) throws Exception {\n        new SingleThread().run(8080);\n    }\n\n    @Override\n    void handle(ClientConnection clientConnection) {\n        clientConnection.run();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/appendix1/ThreadPerConnection.java",
    "content": "package com.oreilly.rxjava.appendix1;\n\nimport java.io.IOException;\n\npublic class ThreadPerConnection extends HttpServer {\n\n    public static void main(String[] args) throws IOException {\n        new ThreadPerConnection().run(8080);\n    }\n\n    @Override\n    void handle(ClientConnection clientConnection) {\n        new Thread(clientConnection).start();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/appendix1/ThreadPool.java",
    "content": "package com.oreilly.rxjava.appendix1;\n\nimport java.io.IOException;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\n\nclass ThreadPool extends HttpServer {\n\n    private final ThreadPoolExecutor executor;\n\n    public static void main(String[] args) throws IOException {\n        new ThreadPool().run(8080);\n    }\n\n    public ThreadPool() {\n        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1000);\n        executor = new ThreadPoolExecutor(100, 100, 0L,\n                                MILLISECONDS, workQueue,\n                (r, ex) -> {\n                    ((ClientConnection) r).serviceUnavailable();\n                });\n    }\n\n    @Override\n    void handle(ClientConnection clientConnection) {\n        executor.execute(clientConnection);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch1/Callback.java",
    "content": "package com.oreilly.rxjava.ch1;\n\nimport java.util.function.Consumer;\n\nclass Callback {\n\tprivate Consumer<String> onResponse = x -> {};\n\tprivate Consumer<Exception> onFailure = x -> {};\n\n\tCallback onResponse(Consumer<String> consumer) {\n\t\tthis.onResponse = consumer;\n\t\treturn this;\n\t}\n\n\tCallback onFailure(Consumer<Exception> consumer) {\n\t\tthis.onFailure = consumer;\n\t\treturn this;\n\t}\n\n\tpublic Consumer<String> getOnResponse() {\n\t\treturn onResponse;\n\t}\n\n\tpublic Consumer<Exception> getOnFailure() {\n\t\treturn onFailure;\n\t}\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch1/Chapter1.java",
    "content": "package com.oreilly.rxjava.ch1;\n\nimport com.oreilly.rxjava.util.Sleeper;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Completable;\nimport rx.Observable;\nimport rx.Single;\nimport rx.schedulers.Schedulers;\n\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\nimport java.util.stream.IntStream;\nimport java.util.stream.Stream;\n\n@Ignore\npublic class Chapter1 {\n\n\tprivate static final String SOME_KEY = \"FOO\";\n\n\t@Test\n\tpublic void sample_6() throws Exception {\n\t\tObservable.create(s -> {\n\t\t\ts.onNext(\"Hello World!\");\n\t\t\ts.onCompleted();\n\t\t}).subscribe(hello -> System.out.println(hello));\n\t}\n\n\t@Test\n\tpublic void sample_17() throws Exception {\n\t\tMap<String, String> cache = new ConcurrentHashMap<>();\n\t\tcache.put(SOME_KEY, \"123\");\n\n\t\tObservable.create(s -> {\n\t\t\ts.onNext(cache.get(SOME_KEY));\n\t\t\ts.onCompleted();\n\t\t}).subscribe(value -> System.out.println(value));\n\t}\n\n\t@Test\n\tpublic void sample_35() throws Exception {\n\t\t// pseudo-code\n\t\tObservable.create(s -> {\n\t\t\tString fromCache = getFromCache(SOME_KEY);\n\t\t\tif (fromCache != null) {\n\t\t\t\t// emit synchronously\n\t\t\t\ts.onNext(fromCache);\n\t\t\t\ts.onCompleted();\n\t\t\t} else {\n\t\t\t\t// fetch asynchronously\n\t\t\t\tgetDataAsynchronously(SOME_KEY)\n\t\t\t\t\t\t.onResponse(v -> {\n\t\t\t\t\t\t\tputInCache(SOME_KEY, v);\n\t\t\t\t\t\t\ts.onNext(v);\n\t\t\t\t\t\t\ts.onCompleted();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.onFailure(exception -> {\n\t\t\t\t\t\t\ts.onError(exception);\n\t\t\t\t\t\t});\n\t\t\t}\n\t\t}).subscribe(s -> System.out.println(s));\n\n\t\tSleeper.sleep(Duration.ofSeconds(2));\n\t}\n\n\tprivate void putInCache(String key, String value) {\n\t\t//do nothing\n\t}\n\n\tprivate Callback getDataAsynchronously(String key) {\n\t\tfinal Callback callback = new Callback();\n\t\tnew Thread(() -> {\n\t\t\tSleeper.sleep(Duration.ofSeconds(1));\n\t\t\tcallback.getOnResponse().accept(key + \":123\");\n\t\t}).start();\n\t\treturn callback;\n\t}\n\n\tprivate String getFromCache(String key) {\n//\t\treturn null;\n\t\treturn key + \":123\";\n\t}\n\n\t@Test\n\tpublic void sample_81() throws Exception {\n\t\tObservable<Integer> o = Observable.create(s -> {\n\t\t\ts.onNext(1);\n\t\t\ts.onNext(2);\n\t\t\ts.onNext(3);\n\t\t\ts.onCompleted();\n\t\t});\n\n\t\to.map(i -> \"Number \" + i)\n\t\t\t\t.subscribe(s -> System.out.println(s));\n\t}\n\n\t@Test\n\tpublic void sample_94() throws Exception {\n\t\tObservable.<Integer>create(s -> {\n\t\t\t//... async subscription and data emission ...\n\t\t\tnew Thread(() -> s.onNext(42), \"MyThread\").start();\n\t\t})\n\t\t\t\t.doOnNext(i -> System.out.println(Thread.currentThread()))\n\t\t\t\t.filter(i -> i % 2 == 0)\n\t\t\t\t.map(i -> \"Value \" + i + \" processed on \" + Thread.currentThread())\n\t\t\t\t.subscribe(s -> System.out.println(\"SOME VALUE =>\" + s));\n\t\tSystem.out.println(\"Will print BEFORE values are emitted because Observable is async\");\n\t\tSleeper.sleep(Duration.ofSeconds(1));\n\t}\n\n\t@Test\n\tpublic void sample_108() throws Exception {\n\t\tObservable.create(s -> {\n\t\t\tnew Thread(() -> {\n\t\t\t\ts.onNext(\"one\");\n\t\t\t\ts.onNext(\"two\");\n\t\t\t\ts.onNext(\"three\");\n\t\t\t\ts.onNext(\"four\");\n\t\t\t\ts.onCompleted();\n\t\t\t}).start();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_121() throws Exception {\n\t\t// DO NOT DO THIS\n\t\tObservable.create(s -> {\n\t\t\t// Thread A\n\t\t\tnew Thread(() -> {\n\t\t\t\ts.onNext(\"one\");\n\t\t\t\ts.onNext(\"two\");\n\t\t\t}).start();\n\n\t\t\t// Thread B\n\t\t\tnew Thread(() -> {\n\t\t\t\ts.onNext(\"three\");\n\t\t\t\ts.onNext(\"four\");\n\t\t\t}).start();\n\n\t\t\t// ignoring need to emit s.onCompleted() due to race of threads\n\t\t});\n\t\t// DO NOT DO THIS\n\t}\n\n\t@Test\n\tpublic void sample_142() throws Exception {\n\t\tObservable<String> a = Observable.create(s -> {\n\t\t\tnew Thread(() -> {\n\t\t\t\ts.onNext(\"one\");\n\t\t\t\ts.onNext(\"two\");\n\t\t\t\ts.onCompleted();\n\t\t\t}).start();\n\t\t});\n\n\t\tObservable<String> b = Observable.create(s -> {\n\t\t\tnew Thread(() -> {\n\t\t\t\ts.onNext(\"three\");\n\t\t\t\ts.onNext(\"four\");\n\t\t\t\ts.onCompleted();\n\t\t\t}).start();\n\t\t});\n\n\t\t// this subscribes to a and b concurrently, and merges into a third sequential stream\n\t\tObservable<String> c = Observable.merge(a, b);\n\t}\n\n\t@Test\n\tpublic void sample_164() throws Exception {\n\t\tString args = SOME_KEY;\n\t\tObservable<String> someData = Observable.create(s -> {\n\t\t\tgetDataFromServerWithCallback(args, data -> {\n\t\t\t\ts.onNext(data);\n\t\t\t\ts.onCompleted();\n\t\t\t});\n\t\t});\n\n\t\tsomeData.subscribe(s -> System.out.println(\"Subscriber 1: \" + s));\n\t\tsomeData.subscribe(s -> System.out.println(\"Subscriber 2: \" + s));\n\n\t\tObservable<String> lazyFallback = Observable.just(\"Fallback\");\n\t\tsomeData\n\t\t\t\t.onErrorResumeNext(lazyFallback)\n\t\t\t\t.subscribe(s -> System.out.println(s));\n\n\t}\n\n\tprivate void getDataFromServerWithCallback(String args, Consumer<String> consumer) {\n\t\tconsumer.accept(\"Random: \" + Math.random());\n\t}\n\n\t@Test\n\tpublic void sample_188() throws Exception {\n\t\t// Iterable<String> as Stream<String>\n\t\t// that contains 75 strings\n\t\tgetDataFromLocalMemorySynchronously()\n\t\t\t\t.skip(10)\n\t\t\t\t.limit(5)\n\t\t\t\t.map(s -> s + \"_transformed\")\n\t\t\t\t.forEach(System.out::println);\n\t}\n\n\tprivate Stream<String> getDataFromLocalMemorySynchronously() {\n\t\treturn IntStream\n\t\t\t\t.range(0, 100)\n\t\t\t\t.mapToObj(Integer::toString);\n\t}\n\n\t@Test\n\tpublic void sample_205() throws Exception {\n\t\t// Observable<String>\n// that emits 75 strings\n\t\tgetDataFromNetworkAsynchronously()\n\t\t\t\t.skip(10)\n\t\t\t\t.take(5)\n\t\t\t\t.map(s -> s + \"_transformed\")\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\tprivate Observable<String> getDataFromNetworkAsynchronously() {\n\t\treturn Observable\n\t\t\t\t.range(0, 100)\n\t\t\t\t.map(Object::toString);\n\t}\n\n\t@Test\n\tpublic void sample_225() throws Exception {\n\t\tCompletableFuture<String> f1 = getDataAsFuture(1);\n\t\tCompletableFuture<String> f2 = getDataAsFuture(2);\n\n\t\tCompletableFuture<String> f3 = f1.thenCombine(f2, (x, y) -> {\n\t\t\treturn x+y;\n\t\t});\n\t}\n\n\tprivate CompletableFuture<String> getDataAsFuture(int i) {\n\t\treturn CompletableFuture.completedFuture(\"Done: \" + i + \"\\n\");\n\t}\n\n\t@Test\n\tpublic void sample_240() throws Exception {\n\t\tObservable<String> o1 = getDataAsObservable(1);\n\t\tObservable<String> o2 = getDataAsObservable(2);\n\n\t\tObservable<String> o3 = Observable.zip(o1, o2, (x, y) -> {\n\t\t\treturn x+y;\n\t\t});\n\t}\n\n\tprivate Observable<String> getDataAsObservable(int i) {\n\t\treturn Observable.just(\"Done: \" + i + \"\\n\");\n\t}\n\n\t@Test\n\tpublic void sample_254() throws Exception {\n\t\tObservable<String> o1 = getDataAsObservable(1);\n\t\tObservable<String> o2 = getDataAsObservable(2);\n\n\t\t// o3 is now a stream of o1 and o2 that emits each item without waiting\n\t\tObservable<String> o3 = Observable.merge(o1, o2);\n\t}\n\n\t@Test\n\tpublic void sample_265() throws Exception {\n\t\t// merge a & b into an Observable stream of 2 values\n\t\tObservable<String> a_merge_b = getDataA().mergeWith(getDataB());\n\t}\n\n\tpublic static Single<String> getDataA() {\n\t\treturn Single.<String> create(o -> {\n\t\t\to.onSuccess(\"DataA\");\n\t\t}).subscribeOn(Schedulers.io());\n\t}\n\n\t@Test\n\tpublic void sample_277() throws Exception {\n\t\t// Observable<String> o1 = getDataAsObservable(1);\n\t\t// Observable<String> o2 = getDataAsObservable(2);\n\n\t\tSingle<String> s1 = getDataAsSingle(1);\n\t\tSingle<String> s2 = getDataAsSingle(2);\n\n\t\t// o3 is now a stream of s1 and s2 that emits each item without waiting\n\t\tObservable<String> o3 = Single.merge(s1, s2);\n\t}\n\n\tprivate Single<String> getDataAsSingle(int i) {\n\t\treturn Single.just(\"Done: \" + i);\n\t}\n\n\tpublic static Single<String> getDataB() {\n\t\treturn Single.just(\"DataB\")\n\t\t\t\t.subscribeOn(Schedulers.io());\n\t}\n\n\tstatic Completable writeToDatabase(Object data) {\n\t\treturn Completable.create(s -> {\n\t\t\tdoAsyncWrite(data,\n\t\t\t\t\t// callback for successful completion\n\t\t\t\t\t() -> s.onCompleted(),\n\t\t\t\t\t// callback for failure with Throwable\n\t\t\t\t\terror -> s.onError(error));\n\t\t});\n\t}\n\n\tstatic void doAsyncWrite(Object data, Runnable onSuccess, Consumer<Exception> onError) {\n\t\t//store data an run asynchronously:\n\t\tonSuccess.run();\n\t}\n\n}\n\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/Chapter2.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nimport com.oreilly.rxjava.util.Sleeper;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Observer;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.subscriptions.Subscriptions;\n\nimport java.math.BigInteger;\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static java.math.BigInteger.ONE;\nimport static java.math.BigInteger.ZERO;\nimport static java.util.concurrent.TimeUnit.MICROSECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\n\n@Ignore\npublic class Chapter2 {\n\n\t@Test\n\tpublic void sample_6() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\ttweets.subscribe((Tweet tweet) ->\n\t\t\t\tSystem.out.println(tweet));\n\t}\n\n\t@Test\n\tpublic void sample_17() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\ttweets.subscribe(\n\t\t\t\t(Tweet tweet) -> { System.out.println(tweet); },\n\t\t\t\t(Throwable t) -> { t.printStackTrace(); }\n\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_27() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\ttweets.subscribe(\n\t\t\t\t(Tweet tweet) -> { System.out.println(tweet); },\n\t\t\t\t(Throwable t) -> { t.printStackTrace(); },\n\t\t\t\t() -> {this.noMore();}\n\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_38() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\t\ttweets.subscribe(\n\t\t\t\tSystem.out::println,\n\t\t\t\tThrowable::printStackTrace,\n\t\t\t\tthis::noMore);\n\t}\n\n\tprivate void noMore() {\n\t}\n\n\t@Test\n\tpublic void sample_51() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\tObserver<Tweet> observer = new Observer<Tweet>() {\n\t\t\t@Override\n\t\t\tpublic void onNext(Tweet tweet) {\n\t\t\t\tSystem.out.println(tweet);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onError(Throwable e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onCompleted() {\n\t\t\t\tnoMore();\n\t\t\t}\n\t\t};\n\n\t\t//...\n\n\t\ttweets.subscribe(observer);\n\t}\n\n\t@Test\n\tpublic void sample_78() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\tSubscription subscription =\n\t\t\t\ttweets.subscribe(System.out::println);\n\n\t\t//...\n\n\t\tsubscription.unsubscribe();\n\t}\n\n\t@Test\n\tpublic void sample_91() throws Exception {\n\t\tObservable<Tweet> tweets = Observable.empty(); //...\n\n\t\tSubscriber<Tweet> subscriber = new Subscriber<Tweet>() {\n\t\t\t@Override\n\t\t\tpublic void onNext(Tweet tweet) {\n\t\t\t\tif (tweet.getText().contains(\"Java\")) {\n\t\t\t\t\tunsubscribe();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onCompleted() {}\n\n\t\t\t@Override\n\t\t\tpublic void onError(Throwable e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t};\n\t\ttweets.subscribe(subscriber);\n\t}\n\n\tprivate static void log(Object msg) {\n\t\tSystem.out.println(\n\t\t\t\tThread.currentThread().getName() +\n\t\t\t\t\t\t\": \" + msg);\n\t}\n\n\t@Test\n\tpublic void sample_117() throws Exception {\n\t\tlog(\"Before\");\n\t\tObservable\n\t\t\t\t.range(5, 3)\n\t\t\t\t.subscribe(i -> {\n\t\t\t\t\tlog(i);\n\t\t\t\t});\n\t\tlog(\"After\");\n\n\t}\n\n\t@Test\n\tpublic void sample_135() throws Exception {\n\t\tObservable<Integer> ints = Observable\n\t\t\t\t.create(new Observable.OnSubscribe<Integer>() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void call(Subscriber<? super Integer> subscriber) {\n\t\t\t\t\t\tlog(\"Create\");\n\t\t\t\t\t\tsubscriber.onNext(5);\n\t\t\t\t\t\tsubscriber.onNext(6);\n\t\t\t\t\t\tsubscriber.onNext(7);\n\t\t\t\t\t\tsubscriber.onCompleted();\n\t\t\t\t\t\tlog(\"Completed\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\tlog(\"Starting\");\n\t\tints.subscribe(i -> log(\"Element: \" + i));\n\t\tlog(\"Exit\");\n\t}\n\n\tstatic <T> Observable<T> just(T x) {\n\t\treturn Observable.create(subscriber -> {\n\t\t\t\t\tsubscriber.onNext(x);\n\t\t\t\t\tsubscriber.onCompleted();\n\t\t\t\t}\n\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_162() throws Exception {\n\t\tObservable<Integer> ints =\n\t\t\t\tObservable.create(subscriber -> {\n\t\t\t\t\t\t\tlog(\"Create\");\n\t\t\t\t\t\t\tsubscriber.onNext(42);\n\t\t\t\t\t\t\tsubscriber.onCompleted();\n\t\t\t\t\t\t}\n\t\t\t\t);\n\t\tlog(\"Starting\");\n\t\tints.subscribe(i -> log(\"Element A: \" + i));\n\t\tints.subscribe(i -> log(\"Element B: \" + i));\n\t\tlog(\"Exit\");\n\t}\n\n\t@Test\n\tpublic void sample_177() throws Exception {\n\t\tObservable<Integer> ints =\n\t\t\t\tObservable.<Integer>create(subscriber -> {\n\t\t\t\t\t\t\t//...\n\t\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\t\t\t.cache();\n\t}\n\n\t@Test\n\tpublic void sample_187() throws Exception {\n\t\t//BROKEN! Don't do this\n\t\tObservable<BigInteger> naturalNumbers = Observable.create(\n\t\t\t\tsubscriber -> {\n\t\t\t\t\tBigInteger i = ZERO;\n\t\t\t\t\twhile (true) {  //don't do this!\n\t\t\t\t\t\tsubscriber.onNext(i);\n\t\t\t\t\t\ti = i.add(ONE);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\tnaturalNumbers.subscribe(x -> log(x));\n\t}\n\n\tprivate Observable<BigInteger> naturalNumbers() {\n\t\tObservable<BigInteger> naturalNumbers = Observable.create(\n\t\t\t\tsubscriber -> {\n\t\t\t\t\tRunnable r = () -> {\n\t\t\t\t\t\tBigInteger i = ZERO;\n\t\t\t\t\t\twhile (!subscriber.isUnsubscribed()) {\n\t\t\t\t\t\t\tsubscriber.onNext(i);\n\t\t\t\t\t\t\ti = i.add(ONE);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\tnew Thread(r).start();\n\t\t\t\t});\n\t\treturn naturalNumbers;\n\t}\n\n\t@Test\n\tpublic void sample_221() throws Exception {\n\t\tfinal Observable<BigInteger> naturalNumbers = naturalNumbers();\n\t\tSubscription subscription = naturalNumbers.subscribe(x -> log(x));\n\t\t//after some time...\n\t\tsubscription.unsubscribe();\n\t}\n\n\tstatic <T> Observable<T> delayed(T x) {\n\t\treturn Observable.create(\n\t\t\t\tsubscriber -> {\n\t\t\t\t\tRunnable r = () -> {\n\t\t\t\t\t\tsleep(10, SECONDS);\n\t\t\t\t\t\tif (!subscriber.isUnsubscribed()) {\n\t\t\t\t\t\t\tsubscriber.onNext(x);\n\t\t\t\t\t\t\tsubscriber.onCompleted();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\tnew Thread(r).start();\n\t\t\t\t});\n\t}\n\n\tstatic void sleep(int timeout, TimeUnit unit) {\n\t\ttry {\n\t\t\tunit.sleep(timeout);\n\t\t} catch (InterruptedException ignored) {\n\t\t\t//intentionally ignored\n\t\t}\n\t}\n\n\tstatic <T> Observable<T> delayed2(T x) {\n\t\treturn Observable.create(\n\t\t\t\tsubscriber -> {\n\t\t\t\t\tRunnable r = () -> {/* ... */};\n\t\t\t\t\tfinal Thread thread = new Thread(r);\n\t\t\t\t\tthread.start();\n\t\t\t\t\tsubscriber.add(Subscriptions.create(thread::interrupt));\n\t\t\t\t});\n\t}\n\n\tObservable<Data> loadAll(Collection<Integer> ids) {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tExecutorService pool = Executors.newFixedThreadPool(10);\n\t\t\tAtomicInteger countDown = new AtomicInteger(ids.size());\n\t\t\t//DANGER, violates Rx contract. Don't do this!\n\t\t\tids.forEach(id -> pool.submit(() -> {\n\t\t\t\tfinal Data data = load(id);\n\t\t\t\tsubscriber.onNext(data);\n\t\t\t\tif (countDown.decrementAndGet() == 0) {\n\t\t\t\t\tpool.shutdownNow();\n\t\t\t\t\tsubscriber.onCompleted();\n\t\t\t\t}\n\t\t\t}));\n\t\t});\n\t}\n\n\tprivate Data load(Integer id) {\n\t\treturn new Data();\n\t}\n\n\tObservable<Data> rxLoad(int id) {\n\t\treturn Observable.create(subscriber -> {\n\t\t\ttry {\n\t\t\t\tsubscriber.onNext(load(id));\n\t\t\t\tsubscriber.onCompleted();\n\t\t\t} catch (Exception e) {\n\t\t\t\tsubscriber.onError(e);\n\t\t\t}\n\t\t});\n\t}\n\n\tObservable<Data> rxLoad2(int id) {\n\t\treturn Observable.fromCallable(() ->\n\t\t\t\tload(id));\n\t}\n\n\t@Test\n\tpublic void sample_304() throws Exception {\n\t\tObservable\n\t\t\t\t.timer(1, TimeUnit.SECONDS)\n\t\t\t\t.subscribe((Long zero) -> log(zero));\n\t\tSleeper.sleep(Duration.ofSeconds(2));\n\t}\n\n\t@Test\n\tpublic void sample_311() throws Exception {\n\t\tObservable\n\t\t\t\t.interval(1_000_000 / 60, MICROSECONDS)\n\t\t\t\t.subscribe((Long i) -> log(i));\n\t\tSleeper.sleep(Duration.ofSeconds(2));\n\t}\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/Config.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.stereotype.Component;\nimport rx.Observable;\nimport rx.observables.ConnectableObservable;\nimport twitter4j.Status;\n\n@Configuration\nclass Config implements ApplicationListener<ContextRefreshedEvent> {\n\n    private static final Logger log = LoggerFactory.getLogger(Config.class);\n\n    private final ConnectableObservable<Status> observable =\n        Observable.<Status>create(subscriber -> {\n            log.info(\"Starting\");\n            //...\n        }).publish();\n\n    @Bean\n    public Observable<Status> observable() {\n        return observable;\n    }\n\n    @Override\n    public void onApplicationEvent(ContextRefreshedEvent event) {\n        log.info(\"Connecting\");\n        observable.connect();\n    }\n}\n\n@Component\nclass Foo {\n\n    private static final Logger log = LoggerFactory.getLogger(Foo.class);\n\n    @Autowired\n    public Foo(Observable<Status> tweets) {\n        tweets.subscribe(status -> {\n            log.info(status.getText());\n        });\n        log.info(\"Subscribed\");\n    }\n}\n\n@Component\nclass Bar {\n\n    private static final Logger log = LoggerFactory.getLogger(Bar.class);\n\n    @Autowired\n    public Bar(Observable<Status> tweets) {\n        tweets.subscribe(status -> {\n            log.info(status.getText());\n        });\n        log.info(\"Subscribed\");\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/Data.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nclass Data {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/LazyTwitterObservable.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.subscriptions.Subscriptions;\nimport twitter4j.*;\n\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\n//DON'T DO THIS, Very brittle and error prone\nclass LazyTwitterObservable {\n\n\tprivate final Set<Subscriber<? super Status>> subscribers =\n\t\t\tnew CopyOnWriteArraySet<>();\n\n\tprivate final TwitterStream twitterStream;\n\n\tpublic LazyTwitterObservable() {\n\t\tthis.twitterStream = new TwitterStreamFactory().getInstance();\n\t\tthis.twitterStream.addListener(new StatusListener() {\n\t\t\t@Override\n\t\t\tpublic void onStatus(Status status) {\n\t\t\t\tsubscribers.forEach(s -> s.onNext(status));\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onTrackLimitationNotice(int numberOfLimitedStatuses) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onScrubGeo(long userId, long upToStatusId) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onStallWarning(StallWarning warning) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onException(Exception ex) {\n\t\t\t\tsubscribers.forEach(s -> s.onError(ex));\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate final Observable<Status> observable = Observable.create(\n\t\t\tsubscriber -> {\n\t\t\t\tregister(subscriber);\n\t\t\t\tsubscriber.add(Subscriptions.create(() ->\n\t\t\t\t\t\tthis.deregister(subscriber)));\n\t\t\t});\n\n\tObservable<Status> observe() {\n\t\treturn observable;\n\t}\n\n\tprivate synchronized void register(Subscriber<? super Status> subscriber) {\n\t\tif (subscribers.isEmpty()) {\n\t\t\tsubscribers.add(subscriber);\n\t\t\ttwitterStream.sample();\n\t\t} else {\n\t\t\tsubscribers.add(subscriber);\n\t\t}\n\t}\n\n\tprivate synchronized void deregister(Subscriber<? super Status> subscriber) {\n\t\tsubscribers.remove(subscriber);\n\t\tif (subscribers.isEmpty()) {\n\t\t\ttwitterStream.shutdown();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/NaturalNumbersIterator.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nimport java.math.BigInteger;\nimport java.util.Iterator;\n\nclass NaturalNumbersIterator implements Iterator<BigInteger> {\n\n\tprivate BigInteger current = BigInteger.ZERO;\n\n\tpublic boolean hasNext() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic BigInteger next() {\n\t\tcurrent = current.add(BigInteger.ONE);\n\t\treturn current;\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/Tweet.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nclass Tweet {\n\n\tprivate final String text;\n\n\tTweet(String text) {\n\t\tthis.text = text;\n\t}\n\n\tString getText() {\n\t\treturn text;\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/TwitterSample.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.observables.ConnectableObservable;\nimport rx.subscriptions.Subscriptions;\nimport twitter4j.*;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\n@Ignore\npublic class TwitterSample {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(TwitterSample.class);\n\n\t@Test\n\tpublic void sample_18() throws Exception {\n\t\tTwitterStream twitterStream = new TwitterStreamFactory().getInstance();\n\t\ttwitterStream.addListener(new twitter4j.StatusListener() {\n\t\t\t@Override\n\t\t\tpublic void onStatus(Status status) {\n\t\t\t\tlog.info(\"Status: {}\", status);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onTrackLimitationNotice(int numberOfLimitedStatuses) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onScrubGeo(long userId, long upToStatusId) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onStallWarning(StallWarning warning) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onException(Exception ex) {\n\t\t\t\tlog.error(\"Error callback\", ex);\n\t\t\t}\n\n\t\t\t//other callbacks\n\t\t});\n\t\ttwitterStream.sample();\n\t\tTimeUnit.SECONDS.sleep(10);\n\t\ttwitterStream.shutdown();\n\t}\n\n\tvoid consume(\n\t\t\tConsumer<Status> onStatus,\n\t\t\tConsumer<Exception> onException) {\n\t\tTwitterStream twitterStream = new TwitterStreamFactory().getInstance();\n\t\ttwitterStream.addListener(new StatusListener() {\n\t\t\t@Override\n\t\t\tpublic void onStatus(Status status) {\n\t\t\t\tonStatus.accept(status);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onTrackLimitationNotice(int numberOfLimitedStatuses) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onScrubGeo(long userId, long upToStatusId) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onStallWarning(StallWarning warning) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onException(Exception ex) {\n\t\t\t\tonException.accept(ex);\n\t\t\t}\n\t\t});\n\t\ttwitterStream.sample();\n\t}\n\n\t@Test\n\tpublic void sample_99() throws Exception {\n\t\tconsume(\n\t\t\t\tstatus -> log.info(\"Status: {}\", status),\n\t\t\t\tex -> log.error(\"Error callback\", ex)\n\t\t);\n\t}\n\n\tObservable<Status> observe() {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tTwitterStream twitterStream =\n\t\t\t\t\tnew TwitterStreamFactory().getInstance();\n\t\t\ttwitterStream.addListener(new StatusListener() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onStatus(Status status) {\n\t\t\t\t\tif (subscriber.isUnsubscribed()) {\n\t\t\t\t\t\ttwitterStream.shutdown();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsubscriber.onNext(status);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {\n\t\t\t\t\t//...\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onTrackLimitationNotice(int numberOfLimitedStatuses) {\n\t\t\t\t\t//...\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onScrubGeo(long userId, long upToStatusId) {\n\t\t\t\t\t//...\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onStallWarning(StallWarning warning) {\n\t\t\t\t\t//...\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onException(Exception ex) {\n\t\t\t\t\tif (subscriber.isUnsubscribed()) {\n\t\t\t\t\t\ttwitterStream.shutdown();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsubscriber.onError(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tsubscriber.add(Subscriptions.create(twitterStream::shutdown));\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_150() throws Exception {\n\t\tobserve().subscribe(\n\t\t\t\tstatus -> log.info(\"Status: {}\", status),\n\t\t\t\tex -> log.error(\"Error callback\", ex)\n\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_162() throws Exception {\n\t\tObservable<Status> observable = status();\n\n\t\tSubscription sub1 = observable.subscribe();\n\t\tSystem.out.println(\"Subscribed 1\");\n\t\tSubscription sub2 = observable.subscribe();\n\t\tSystem.out.println(\"Subscribed 2\");\n\t\tsub1.unsubscribe();\n\t\tSystem.out.println(\"Unsubscribed 1\");\n\t\tsub2.unsubscribe();\n\t\tSystem.out.println(\"Unsubscribed 2\");\n\t}\n\n\tprivate Observable<Status> status() {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tSystem.out.println(\"Establishing connection\");\n\t\t\tTwitterStream twitterStream = new TwitterStreamFactory().getInstance();\n\t\t\t//...\n\t\t\tsubscriber.add(Subscriptions.create(() -> {\n\t\t\t\tSystem.out.println(\"Disconnecting\");\n\t\t\t\ttwitterStream.shutdown();\n\t\t\t}));\n\t\t\ttwitterStream.sample();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_186() throws Exception {\n\t\tObservable<Status> observable = status();\n\t\tObservable<Status> lazy = observable.publish().refCount();\n\t\t//...\n\t\tSystem.out.println(\"Before subscribers\");\n\t\tSubscription sub1 = lazy.subscribe();\n\t\tSystem.out.println(\"Subscribed 1\");\n\t\tSubscription sub2 = lazy.subscribe();\n\t\tSystem.out.println(\"Subscribed 2\");\n\t\tsub1.unsubscribe();\n\t\tSystem.out.println(\"Unsubscribed 1\");\n\t\tsub2.unsubscribe();\n\t\tSystem.out.println(\"Unsubscribed 2\");\n\t}\n\n\t@Test\n\tpublic void sample_206() throws Exception {\n\t\tfinal Observable<Status> tweets = status();\n\t\tConnectableObservable<Status> published = tweets.publish();\n\t\tpublished.connect();\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch2/TwitterSubject.java",
    "content": "package com.oreilly.rxjava.ch2;\n\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport twitter4j.*;\n\nclass TwitterSubject {\n\n\tprivate final PublishSubject<Status> subject = PublishSubject.create();\n\n\tpublic TwitterSubject() {\n\t\tTwitterStream twitterStream = new TwitterStreamFactory().getInstance();\n\t\ttwitterStream.addListener(new StatusListener() {\n\t\t\t@Override\n\t\t\tpublic void onStatus(Status status) {\n\t\t\t\tsubject.onNext(status);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onTrackLimitationNotice(int numberOfLimitedStatuses) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onScrubGeo(long userId, long upToStatusId) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onStallWarning(StallWarning warning) {\n\t\t\t\t//...\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onException(Exception ex) {\n\t\t\t\tsubject.onError(ex);\n\t\t\t}\n\n\t\t});\n\t\ttwitterStream.sample();\n\t}\n\n\tpublic Observable<Status> observe() {\n\t\treturn subject;\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Car.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Car {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/CarPhoto.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass CarPhoto {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/CashTransfer.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport java.math.BigDecimal;\n\nclass CashTransfer {\n\n\tBigDecimal getAmount() {\n\t\treturn BigDecimal.ONE;\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/CassandraFactStore.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport rx.Observable;\n\nclass CassandraFactStore implements FactStore {\n\t@Override\n\tpublic Observable<ReservationEvent> observe() {\n\t\treturn Observable.just(new ReservationEvent());\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Chapter3.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport com.oreilly.rxjava.util.Sleeper;\nimport org.apache.commons.lang3.RandomUtils;\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.functions.Func1;\nimport twitter4j.Status;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.time.DayOfWeek;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.LongAdder;\n\nimport static com.oreilly.rxjava.ch3.Sound.DAH;\nimport static com.oreilly.rxjava.ch3.Sound.DI;\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static rx.Observable.*;\n\n@Ignore\npublic class Chapter3 {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Chapter3.class);\n\n\t@Test\n\tpublic void sample_6() throws Exception {\n\t\tObservable<String> strings = empty();\n\t\tObservable<String> filtered = strings.filter(s -> s.startsWith(\"#\"));\n\t}\n\n\t@Test\n\tpublic void sample_15() throws Exception {\n\t\tObservable<String> strings = empty();\n\t\tObservable<String> comments = strings.filter(s -> s.startsWith(\"#\"));\n\t\tObservable<String> instructions = strings.filter(s -> s.startsWith(\">\"));\n\t\tObservable<String> empty = strings.filter(String::isEmpty);\n\t}\n\n\t@Test\n\tpublic void sample_26() throws Exception {\n\t\tObservable<Status> tweets = empty();\n\t\tObservable<Date> dates = tweets.map(new Func1<Status, Date>() {\n\t\t\t@Override\n\t\t\tpublic Date call(Status status) {\n\t\t\t\treturn status.getCreatedAt();\n\t\t\t}\n\t\t});\n\n\t\tObservable<Date> dates2 =\n\t\t\t\ttweets.map((Status status) -> status.getCreatedAt());\n\n\t\tObservable<Date> dates3 =\n\t\t\t\ttweets.map((status) -> status.getCreatedAt());\n\n\t\tObservable<Date> dates4 =\n\t\t\t\ttweets.map(Status::getCreatedAt);\n\t}\n\n\t@Test\n\tpublic void sample_49() throws Exception {\n\t\tObservable<Status> tweets = empty();\n\n\t\tObservable<Instant> instants = tweets\n\t\t\t\t.map(Status::getCreatedAt)\n\t\t\t\t.map((Date d) -> d.toInstant());\n\t}\n\n\t@Test\n\tpublic void sample_57() throws Exception {\n\t\tjust(8, 9, 10)\n\t\t\t\t.filter(i -> i % 3 > 0)\n\t\t\t\t.map(i -> \"#\" + i * 10)\n\t\t\t\t.filter(s -> s.length() < 4);\n\t}\n\n\t@Test\n\tpublic void sample_66() throws Exception {\n\t\tjust(8, 9, 10)\n\t\t\t\t.doOnNext(i -> System.out.println(\"A: \" + i))\n\t\t\t\t.filter(i -> i % 3 > 0)\n\t\t\t\t.doOnNext(i -> System.out.println(\"B: \" + i))\n\t\t\t\t.map(i -> \"#\" + i * 10)\n\t\t\t\t.doOnNext(s -> System.out.println(\"C: \" + s))\n\t\t\t\t.filter(s -> s.length() < 4)\n\t\t\t\t.subscribe(s -> System.out.println(\"D: \" + s));\n\t}\n\n\t@Test\n\tpublic void sample_79() throws Exception {\n\t\tObservable<Integer> numbers = just(1, 2, 3, 4);\n\n\t\tnumbers.map(x -> x * 2);\n\t\tnumbers.filter(x -> x != 10);\n\n\t\t//equivalent\n\t\tnumbers.flatMap(x -> just(x * 2));\n\t\tnumbers.flatMap(x -> (x != 10) ? just(x) : empty());\n\t}\n\n\t@Test\n\tpublic void sample_111() throws Exception {\n\t\tObservable<Customer> customers = Observable.just(new Customer());\n\t\tObservable<Order> orders = customers\n\t\t\t\t.flatMap(customer ->\n\t\t\t\t\t\tObservable.from(customer.getOrders()));\n\t}\n\n\t@Test\n\tpublic void sample_119() throws Exception {\n\t\tObservable<Customer> customers = Observable.just(new Customer());\n\t\tObservable<Order> orders = customers\n\t\t\t\t.map(Customer::getOrders)\n\t\t\t\t.flatMap(Observable::from);\n\t}\n\n\t@Test\n\tpublic void sample_127() throws Exception {\n\t\tObservable<Customer> customers = Observable.just(new Customer());\n\t\tObservable<Order> orders = customers\n\t\t\t\t.flatMapIterable(Customer::getOrders);\n\t}\n\n\tvoid store(UUID id) {\n\t\tupload(id).subscribe(\n\t\t\t\tbytes -> {\n\t\t\t\t}, //ignore\n\t\t\t\te -> log.error(\"Error\", e),\n\t\t\t\t() -> rate(id)\n\t\t);\n\t}\n\n\tObservable<Long> upload(UUID id) {\n\t\treturn Observable.just(42L);\n\t}\n\n\tObservable<Rating> rate(UUID id) {\n\t\treturn Observable.just(new Rating());\n\t}\n\n\t@Test\n\tpublic void sample_155() throws Exception {\n\t\tUUID id = UUID.randomUUID();\n\t\tupload(id)\n\t\t\t\t.flatMap(\n\t\t\t\t\t\tbytes -> Observable.empty(),\n\t\t\t\t\t\te -> Observable.error(e),\n\t\t\t\t\t\t() -> rate(id)\n\t\t\t\t);\n\t}\n\n\tObservable<Sound> toMorseCode(char ch) {\n\t\tswitch (ch) {\n\t\t\tcase 'a':\n\t\t\t\treturn just(DI, DAH);\n\t\t\tcase 'b':\n\t\t\t\treturn just(DAH, DI, DI, DI);\n\t\t\tcase 'c':\n\t\t\t\treturn just(DAH, DI, DAH, DI);\n\t\t\tcase 'd':\n\t\t\t\treturn just(DAH, DI, DI);\n\t\t\tcase 'e':\n\t\t\t\treturn just(DI);\n\t\t\tcase 'f':\n\t\t\t\treturn just(DI, DI, DAH, DI);\n\t\t\tcase 'g':\n\t\t\t\treturn just(DAH, DAH, DI);\n\t\t\tcase 'h':\n\t\t\t\treturn just(DI, DI, DI, DI);\n\t\t\tcase 'i':\n\t\t\t\treturn just(DI, DI);\n\t\t\tcase 'j':\n\t\t\t\treturn just(DI, DAH, DAH, DAH);\n\t\t\tcase 'k':\n\t\t\t\treturn just(DAH, DI, DAH);\n\t\t\tcase 'l':\n\t\t\t\treturn just(DI, DAH, DI, DI);\n\t\t\tcase 'm':\n\t\t\t\treturn just(DAH, DAH);\n\t\t\tcase 'n':\n\t\t\t\treturn just(DAH, DI);\n\t\t\tcase 'o':\n\t\t\t\treturn just(DAH, DAH, DAH);\n\t\t\tcase 'p':\n\t\t\t\treturn just(DI, DAH, DAH, DI);\n\t\t\tcase 'q':\n\t\t\t\treturn just(DAH, DAH, DI, DAH);\n\t\t\tcase 'r':\n\t\t\t\treturn just(DI, DAH, DI);\n\t\t\tcase 's':\n\t\t\t\treturn just(DI, DI, DI);\n\t\t\tcase 't':\n\t\t\t\treturn just(DAH);\n\t\t\tcase 'u':\n\t\t\t\treturn just(DI, DI, DAH);\n\t\t\tcase 'v':\n\t\t\t\treturn just(DI, DI, DI, DAH);\n\t\t\tcase 'w':\n\t\t\t\treturn just(DI, DAH, DAH);\n\t\t\tcase 'x':\n\t\t\t\treturn just(DAH, DI, DI, DAH);\n\t\t\tcase 'y':\n\t\t\t\treturn just(DAH, DI, DAH, DAH);\n\t\t\tcase 'z':\n\t\t\t\treturn just(DAH, DAH, DI, DI);\n\t\t\tcase '0':\n\t\t\t\treturn just(DAH, DAH, DAH, DAH, DAH);\n\t\t\tcase '1':\n\t\t\t\treturn just(DI, DAH, DAH, DAH, DAH);\n\t\t\tcase '2':\n\t\t\t\treturn just(DI, DI, DAH, DAH, DAH);\n\t\t\tcase '3':\n\t\t\t\treturn just(DI, DI, DI, DAH, DAH);\n\t\t\tcase '4':\n\t\t\t\treturn just(DI, DI, DI, DI, DAH);\n\t\t\tcase '5':\n\t\t\t\treturn just(DI, DI, DI, DI, DI);\n\t\t\tcase '6':\n\t\t\t\treturn just(DAH, DI, DI, DI, DI);\n\t\t\tcase '7':\n\t\t\t\treturn just(DAH, DAH, DI, DI, DI);\n\t\t\tcase '8':\n\t\t\t\treturn just(DAH, DAH, DAH, DI, DI);\n\t\t\tcase '9':\n\t\t\t\treturn just(DAH, DAH, DAH, DAH, DI);\n\t\t\tdefault:\n\t\t\t\treturn empty();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void sample_213() throws Exception {\n\t\tjust('S', 'p', 'a', 'r', 't', 'a')\n\t\t\t\t.map(Character::toLowerCase)\n\t\t\t\t.flatMap(this::toMorseCode);\n\t}\n\n\t@Test\n\tpublic void sample_218() throws Exception {\n\t\tObservable\n\t\t\t\t.just(\"Lorem\", \"ipsum\", \"dolor\", \"sit\", \"amet\",\n\t\t\t\t\t\t\"consectetur\", \"adipiscing\", \"elit\")\n\t\t\t\t.delay(word -> timer(word.length(), SECONDS))\n\t\t\t\t.subscribe(System.out::println);\n\n\t\tSECONDS.sleep(15);\n\t}\n\n\tObservable<String> loadRecordsFor(DayOfWeek dow) {\n\t\tswitch (dow) {\n\t\t\tcase SUNDAY:\n\t\t\t\treturn\n\t\t\t\t\t\tinterval(90, MILLISECONDS)\n\t\t\t\t\t\t\t\t.take(5)\n\t\t\t\t\t\t\t\t.map(i -> \"Sun-\" + i);\n\t\t\tcase MONDAY:\n\t\t\t\treturn\n\t\t\t\t\t\tinterval(65, MILLISECONDS)\n\t\t\t\t\t\t\t\t.take(5)\n\t\t\t\t\t\t\t\t.map(i -> \"Mon-\" + i);\n\t\t\tdefault:\n\t\t\t\tthrow new IllegalArgumentException(\"Illegal: \" + dow);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void sample_249() throws Exception {\n\t\tObservable\n\t\t\t\t.just(DayOfWeek.SUNDAY, DayOfWeek.MONDAY)\n\t\t\t\t.concatMap(this::loadRecordsFor);\n\n\t}\n\n\t@Test\n\tpublic void sample_258() throws Exception {\n\t\tList<User> veryLargeList = Arrays.asList(new User(), new User(), new User(), new User());\n\t\tObservable<Profile> profiles = Observable\n\t\t\t\t.from(veryLargeList)\n\t\t\t\t.flatMap(User::loadProfile);\n\t}\n\n\t@Test\n\tpublic void sample_286() throws Exception {\n\t\tfinal WeatherStation station = new BasicWeatherStation();\n\n\t\tObservable<Temperature> temperatureMeasurements = station.temperature();\n\t\tObservable<Wind> windMeasurements = station.wind();\n\n\t\ttemperatureMeasurements\n\t\t\t\t.zipWith(windMeasurements,\n\t\t\t\t\t\t(temperature, wind) -> new Weather(temperature, wind));\n\t}\n\n\t@Test\n\tpublic void sample_298() throws Exception {\n\t\tObservable<Integer> oneToEight = Observable.range(1, 8);\n\t\tObservable<String> ranks = oneToEight\n\t\t\t\t.map(Object::toString);\n\t\tObservable<String> files = oneToEight\n\t\t\t\t.map(x -> 'a' + x - 1)\n\t\t\t\t.map(ascii -> (char) ascii.intValue())\n\t\t\t\t.map(ch -> Character.toString(ch));\n\n\t\tObservable<String> squares = files\n\t\t\t\t.flatMap(file -> ranks.map(rank -> file + rank));\n\t}\n\n\t@Test\n\tpublic void sample_312() throws Exception {\n\t\tObservable<LocalDate> nextTenDays =\n\t\t\t\tObservable\n\t\t\t\t\t\t.range(1, 10)\n\t\t\t\t\t\t.map(i -> LocalDate.now().plusDays(i));\n\n\t\tObservable<Vacation> possibleVacations = Observable\n\t\t\t\t.just(City.Warsaw, City.London, City.Paris)\n\t\t\t\t.flatMap(city -> nextTenDays.map(date -> new Vacation(city, date))\n\t\t\t\t\t\t.flatMap(vacation ->\n\t\t\t\t\t\t\t\tObservable.zip(\n\t\t\t\t\t\t\t\t\t\tvacation.weather().filter(Weather::isSunny),\n\t\t\t\t\t\t\t\t\t\tvacation.cheapFlightFrom(City.NewYork),\n\t\t\t\t\t\t\t\t\t\tvacation.cheapHotel(),\n\t\t\t\t\t\t\t\t\t\t(w, f, h) -> vacation\n\t\t\t\t\t\t\t\t)));\n\t}\n\n\t@Test\n\tpublic void sample_332() throws Exception {\n\t\tObservable<Long> red = interval(10, TimeUnit.MILLISECONDS);\n\t\tObservable<Long> green = interval(10, TimeUnit.MILLISECONDS);\n\n\t\tObservable.zip(\n\t\t\t\tred.timestamp(),\n\t\t\t\tgreen.timestamp(),\n\t\t\t\t(r, g) -> r.getTimestampMillis() - g.getTimestampMillis()\n\t\t).forEach(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_345() throws Exception {\n\t\tObservable.combineLatest(\n\t\t\t\tinterval(17, MILLISECONDS).map(x -> \"S\" + x),\n\t\t\t\tinterval(10, MILLISECONDS).map(x -> \"F\" + x),\n\t\t\t\t(s, f) -> f + \":\" + s\n\t\t).forEach(System.out::println);\n\t\tSleeper.sleep(Duration.ofSeconds(2));\n\t}\n\n\t@Test\n\tpublic void sample_355() throws Exception {\n\t\tObservable<String> fast = interval(10, MILLISECONDS)\n\t\t\t\t.map(x -> \"F\" + x)\n\t\t\t\t.delay(100, MILLISECONDS)\n\t\t\t\t.startWith(\"FX\");\n\t\tObservable<String> slow = interval(17, MILLISECONDS).map(x -> \"S\" + x);\n\t\tslow\n\t\t\t\t.withLatestFrom(fast, (s, f) -> s + \":\" + f)\n\t\t\t\t.forEach(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_367() throws Exception {\n\t\tObservable\n\t\t\t\t.just(1, 2)\n\t\t\t\t.startWith(0)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\tObservable<String> stream(int initialDelay, int interval, String name) {\n\t\treturn Observable\n\t\t\t\t.interval(initialDelay, interval, MILLISECONDS)\n\t\t\t\t.map(x -> name + x)\n\t\t\t\t.doOnSubscribe(() ->\n\t\t\t\t\t\tlog.info(\"Subscribe to \" + name))\n\t\t\t\t.doOnUnsubscribe(() ->\n\t\t\t\t\t\tlog.info(\"Unsubscribe from \" + name));\n\t}\n\n\t@Test\n\tpublic void sample_375() throws Exception {\n\t\tObservable.amb(\n\t\t\t\tstream(100, 17, \"S\"),\n\t\t\t\tstream(200, 10, \"F\")\n\t\t).subscribe(log::info);\n\t}\n\n\t@Test\n\tpublic void sample_393() throws Exception {\n\t\tstream(100, 17, \"S\")\n\t\t\t\t.ambWith(stream(200, 10, \"F\"))\n\t\t\t\t.subscribe(log::info);\n\t}\n\n\t@Test\n\tpublic void sample_400() throws Exception {\n\t\t//BROKEN!\n\t\tObservable<Long> progress = transferFile();\n\n\t\tLongAdder total = new LongAdder();\n\t\tprogress.subscribe(total::add);\n\t\tSleeper.sleep(Duration.ofSeconds(10));\n\t}\n\n\tprivate Observable<Long> transferFile() {\n\t\treturn Observable\n\t\t\t\t.interval(500, MILLISECONDS)\n\t\t\t\t.map(x -> RandomUtils.nextLong(10, 30))\n\t\t\t\t.take(100);\n\t}\n\n\t@Test\n\tpublic void sample_419() throws Exception {\n\t\tObservable<Long> progress = transferFile();\n\n\t\tObservable<Long> totalProgress = progress\n\t\t\t\t.scan((total, chunk) -> total + chunk);\n\n\t\ttotalProgress\n\t\t\t\t.toBlocking()\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_431() throws Exception {\n\t\tObservable<BigInteger> factorials = Observable\n\t\t\t\t.range(2, 100)\n\t\t\t\t.scan(BigInteger.ONE, (big, cur) ->\n\t\t\t\t\t\tbig.multiply(BigInteger.valueOf(cur)));\n\t}\n\n\t@Test\n\tpublic void sample_440() throws Exception {\n\t\tObservable<CashTransfer> transfers = Observable.just(new CashTransfer());\n\n\n\t\tObservable<BigDecimal> total1 = transfers\n\t\t\t\t.reduce(BigDecimal.ZERO,\n\t\t\t\t\t\t(totalSoFar, transfer) ->\n\t\t\t\t\t\t\t\ttotalSoFar.add(transfer.getAmount()));\n\n\t\tObservable<BigDecimal> total2 = transfers\n\t\t\t\t.map(CashTransfer::getAmount)\n\t\t\t\t.reduce(BigDecimal.ZERO, BigDecimal::add);\n\t}\n\n\t@Test\n\tpublic void sample_456() throws Exception {\n\t\tObservable<List<Integer>> all = Observable\n\t\t\t\t.range(10, 20)\n\t\t\t\t.reduce(new ArrayList<>(), (list, item) -> {\n\t\t\t\t\tlist.add(item);\n\t\t\t\t\treturn list;\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_463() throws Exception {\n\t\tObservable<List<Integer>> all = Observable\n\t\t\t\t.range(10, 20)\n\t\t\t\t.collect(ArrayList::new, List::add);\n\t}\n\n\t@Test\n\tpublic void sample_470() throws Exception {\n\t\tObservable<String> str = Observable\n\t\t\t\t.range(1, 10)\n\t\t\t\t.collect(\n\t\t\t\t\t\tStringBuilder::new,\n\t\t\t\t\t\t(sb, x) -> sb.append(x).append(\", \"))\n\t\t\t\t.map(StringBuilder::toString);\n\t}\n\n\n\tprivate Observable<Integer> randomInts() {\n\t\tObservable<Integer> randomInts = Observable.create(subscriber -> {\n\t\t\tRandom random = new Random();\n\t\t\twhile (!subscriber.isUnsubscribed()) {\n\t\t\t\tsubscriber.onNext(random.nextInt(1000));\n\t\t\t}\n\t\t});\n\t\treturn randomInts;\n\t}\n\n\t@Test\n\tpublic void sample_490() throws Exception {\n\t\tfinal Observable<Integer> randomInts = randomInts();\n\t\tObservable<Integer> uniqueRandomInts = randomInts\n\t\t\t\t.distinct()\n\t\t\t\t.take(10);\n\t}\n\n\t@Test\n\tpublic void sample_499() throws Exception {\n\t\tObservable<Status> tweets = Observable.empty();\n\n\t\tObservable<Long> distinctUserIds = tweets\n\t\t\t\t.map(status -> status.getUser().getId())\n\t\t\t\t.distinct();\n\t}\n\n\t@Test\n\tpublic void sample_508() throws Exception {\n\t\tObservable<Status> tweets = Observable.empty();\n\n\t\tObservable<Status> distinctUserIds = tweets\n\t\t\t\t.distinct(status -> status.getUser().getId());\n\t}\n\n\t@Test\n\tpublic void sample_516() throws Exception {\n\t\tObservable<Weather> measurements = Observable.empty();\n\n\t\tObservable<Weather> tempChanges = measurements\n\t\t\t\t.distinctUntilChanged(Weather::getTemperature);\n\t}\n\n\t@Test\n\tpublic void sample_524() throws Exception {\n\t\tObservable.range(1, 5).take(3);  // [1, 2, 3]\n\t\tObservable.range(1, 5).skip(3);  // [4, 5]\n\t\tObservable.range(1, 5).skip(5);  // []\n\t}\n\n\t@Test\n\tpublic void sample_531() throws Exception {\n\t\tObservable.range(1, 5).takeLast(2);  // [4, 5]\n\t\tObservable.range(1, 5).skipLast(2);  // [1, 2, 3]\n\t}\n\n\t@Test\n\tpublic void sample_537() throws Exception {\n\t\tObservable.range(1, 5).takeUntil(x -> x == 3);  // [1, 2, 3]\n\t\tObservable.range(1, 5).takeWhile(x -> x != 3);  // [1, 2]\n\t}\n\n\t@Test\n\tpublic void sample_543() throws Exception {\n\t\tObservable<Integer> size = Observable\n\t\t\t\t.just('A', 'B', 'C', 'D')\n\t\t\t\t.reduce(0, (sizeSoFar, ch) -> sizeSoFar + 1);\n\t}\n\n\t@Test\n\tpublic void sample_550() throws Exception {\n\t\tObservable<Integer> numbers = Observable.range(1, 5);\n\n\t\tnumbers.all(x -> x != 4);    // [false]\n\t\tnumbers.exists(x -> x == 4); // [true]\n\t\tnumbers.contains(4);         // [true]\n\t}\n\n\t@Test\n\tpublic void sample_559() throws Exception {\n\t\tObservable<Data> veryLong = Observable\n\t\t\t\t.range(0, 1_000)\n\t\t\t\t.map(x -> new Data());\n\t\tfinal Observable<Data> ends = Observable.concat(\n\t\t\t\tveryLong.take(5),\n\t\t\t\tveryLong.takeLast(5)\n\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_570() throws Exception {\n\t\tObservable<Car> fromCache = loadFromCache();\n\t\tObservable<Car> fromDb = loadFromDb();\n\n\t\tObservable<Car> found = Observable\n\t\t\t\t.concat(fromCache, fromDb)\n\t\t\t\t.first();\n\n\t}\n\n\tprivate Observable<Car> loadFromDb() {\n\t\treturn Observable.just(new Car());\n\t}\n\n\tprivate Observable<Car> loadFromCache() {\n\t\treturn Observable.just(new Car());\n\t}\n\n\t@Test\n\tpublic void sample_589() throws Exception {\n\t\tObservable<Boolean> trueFalse = Observable.just(true, false).repeat();\n\t\tObservable<Integer> upstream = Observable.range(30, 8);\n\t\tObservable<Integer> downstream = upstream\n\t\t\t\t.zipWith(trueFalse, Pair::of)\n\t\t\t\t.filter(Pair::getRight)\n\t\t\t\t.map(Pair::getLeft);\n\t}\n\n\t@Test\n\tpublic void sample_600() throws Exception {\n\t\tObservable<Boolean> trueFalse = Observable.just(true, false).repeat();\n\t\tObservable<Integer> upstream = Observable.range(30, 8);\n\n\t\tupstream.zipWith(trueFalse, (t, bool) ->\n\t\t\t\tbool ? just(t) : empty())\n\t\t\t\t.flatMap(obs -> obs);\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/City.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nenum City {\n\n\tWarsaw, London, Paris, NewYork\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/CustomOperators.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport static rx.Observable.just;\n\n@Ignore\npublic class CustomOperators {\n\n\tstatic <T> Observable<T> odd(Observable<T> upstream) {\n\t\tObservable<Boolean> trueFalse = just(true, false).repeat();\n\t\treturn upstream\n\t\t\t\t.zipWith(trueFalse, Pair::of)\n\t\t\t\t.filter(Pair::getRight)\n\t\t\t\t.map(Pair::getLeft);\n\t}\n\n\tprivate <T> Observable.Transformer<T, T> odd() {\n\t\tObservable<Boolean> trueFalse = just(true, false).repeat();\n\t\treturn upstream -> upstream\n\t\t\t\t.zipWith(trueFalse, Pair::of)\n\t\t\t\t.filter(Pair::getRight)\n\t\t\t\t.map(Pair::getLeft);\n\t}\n\t\n\t@Test\n\tpublic void sample_618() throws Exception {\n\t\t//[A, B, C, D, E...]\n\t\tObservable<Character> alphabet =\n\t\t\t\tObservable\n\t\t\t\t\t\t.range(0, 'Z' - 'A' + 1)\n\t\t\t\t\t\t.map(c -> (char) ('A' + c));\n\n\t\t//[A, C, E, G, I...]\n\t\talphabet\n\t\t\t\t.compose(odd())\n\t\t\t\t.forEach(System.out::println);\n\n\t}\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 1000)\n\t\t\t\t.filter(x -> x % 3 == 0)\n\t\t\t\t.distinct()\n\t\t\t\t.reduce((a, x) -> a + x)\n\t\t\t\t.map(Integer::toHexString)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_59() throws Exception {\n\t\tObservable<String> odd = Observable\n\t\t\t\t.range(1, 9)\n\t\t\t\t.lift(toStringOfOdd());\n\t\t//Will emit: \"1\", \"3\", \"5\", \"7\" and \"9\" strings\n\n\t\todd.subscribe(System.out::println);\n\t}\n\n\t<T> Observable.Operator<String, T> toStringOfOdd() {\n\t\treturn new Observable.Operator<String, T>() {\n\n\t\t\tprivate boolean odd = true;\n\n\t\t\t@Override\n\t\t\tpublic Subscriber<? super T> call(Subscriber<? super String> child) {\n\t\t\t\treturn new Subscriber<T>(child) {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onCompleted() {\n\t\t\t\t\t\tchild.onCompleted();\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onError(Throwable e) {\n\t\t\t\t\t\tchild.onError(e);\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onNext(T t) {\n\t\t\t\t\t\tif(odd) {\n\t\t\t\t\t\t\tchild.onNext(t.toString());\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trequest(1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\todd = !odd;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\t}\n\n\n\t@Test\n\tpublic void sample_67() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 9)\n\t\t\t\t.buffer(1, 2)\n\t\t\t\t.concatMapIterable(x -> x)\n\t\t\t\t.map(Object::toString);\n\t}\n\n\t@Test\n\tpublic void sample_112() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 4)\n\t\t\t\t.repeat()\n\t\t\t\t.lift(toStringOfOdd())\n\t\t\t\t.take(3)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tSystem.out::println,\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> System.out.println(\"Completed\")\n\t\t\t\t);\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Customer.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nclass Customer {\n\n\tList<Order> getOrders() {\n\t\treturn Arrays.asList(new Order(), new Order());\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Data.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Data {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/FactStore.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport rx.Observable;\n\ninterface FactStore {\n\tObservable<ReservationEvent> observe();\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Flight.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Flight {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Hotel.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Hotel {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/LicensePlate.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass LicensePlate {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Licenses.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\n\n@Ignore\npublic class Licenses {\n\n\tObservable<CarPhoto> cars() {\n\t\treturn Observable.just(new CarPhoto());\n\t}\n\n\tObservable<LicensePlate> recognize(CarPhoto photo) {\n\t\treturn Observable.just(new LicensePlate());\n\t}\n\n\t@Test\n\tpublic void sample_100() throws Exception {\n\t\tObservable<CarPhoto> cars = cars();\n\n\t\tObservable<Observable<LicensePlate>> plates =\n\t\t\t\tcars.map(this::recognize);\n\n\t\tObservable<LicensePlate> plates2 =\n\t\t\t\tcars.flatMap(this::recognize);\n\t}\n\n\n\tObservable<LicensePlate> fastAlgo(CarPhoto photo) {\n\t\t//Fast but poor quality\n\t\treturn Observable.just(new LicensePlate());\n\t}\n\n\tObservable<LicensePlate> preciseAlgo(CarPhoto photo) {\n\t\t//Precise but can be expensive\n\t\treturn Observable.just(new LicensePlate());\n\t}\n\n\tObservable<LicensePlate> experimentalAlgo(CarPhoto photo) {\n\t\t//Unpredictable, running anyway\n\t\treturn Observable.just(new LicensePlate());\n\t}\n\n\t@Test\n\tpublic void sample_317() throws Exception {\n\t\tCarPhoto photo = new CarPhoto();\n\t\tObservable<LicensePlate> all = Observable.merge(\n\t\t\t\tpreciseAlgo(photo),\n\t\t\t\tfastAlgo(photo),\n\t\t\t\texperimentalAlgo(photo)\n\t\t);\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/OperatorMap.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func1;\n\nfinal class OperatorMap<T, R> implements Observable.Operator<R, T> {\n\n    private final Func1<T, R> transformer;\n\n    public OperatorMap(Func1<T, R> transformer) {\n        this.transformer = transformer;\n    }\n\n    @Override\n    public Subscriber<? super T> call(Subscriber<? super R> child) {\n        return new Subscriber<T>(child) {\n\n            @Override\n            public void onCompleted() {\n                child.onCompleted();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                child.onError(e);\n            }\n\n            @Override\n            public void onNext(T t) {\n                try {\n                    child.onNext(transformer.call(t));\n                } catch (Exception e) {\n                    onError(e);\n                }\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Order.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Order {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Profile.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Profile {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Rating.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Rating {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Reservation.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Reservation {\n\n    Reservation consume(ReservationEvent event) {\n        //mutate myself\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/ReservationEvent.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport java.util.UUID;\n\nclass ReservationEvent {\n\tprivate final UUID uuid = UUID.randomUUID();\n\tpublic UUID getReservationUuid() {\n\t\treturn uuid;\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Reservations.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.observables.GroupedObservable;\n\nimport java.util.Optional;\nimport java.util.UUID;\n\n@Ignore\npublic class Reservations {\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tFactStore factStore = new CassandraFactStore();\n\t\tObservable<ReservationEvent> facts = factStore.observe();\n\t\tfacts.subscribe(this::updateProjection);\n\t}\n\n\tvoid updateProjection(ReservationEvent event) {\n\n\t}\n\n\tprivate void store(UUID id, Reservation modified) {\n\t\t//...\n\t}\n\n\tOptional<Reservation> loadBy(UUID uuid) {\n\t\t//...\n\t\treturn Optional.of(new Reservation());\n\t}\n\n\t@Test\n\tpublic void sample_34() throws Exception {\n\t\tFactStore factStore = new CassandraFactStore();\n\n\t\tObservable<ReservationEvent> facts = factStore.observe();\n\n\t\tfacts\n\t\t\t\t.flatMap(this::updateProjectionAsync)\n\t\t\t\t.subscribe();\n\n\t\t//...\n\t}\n\n\tObservable<ReservationEvent> updateProjectionAsync(ReservationEvent event) {\n\t\t//possibly asynchronous\n\t\treturn Observable.just(new ReservationEvent());\n\t}\n\n\t@Test\n\tpublic void sample_52() throws Exception {\n\t\tFactStore factStore = new CassandraFactStore();\n\n\t\tObservable<ReservationEvent> facts = factStore.observe();\n\n\t\tObservable<GroupedObservable<UUID, ReservationEvent>> grouped =\n\t\t\t\tfacts.groupBy(ReservationEvent::getReservationUuid);\n\n\t\tgrouped.subscribe(byUuid -> {\n\t\t\tbyUuid.subscribe(this::updateProjection);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Shakespeare.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport com.oreilly.rxjava.util.Sleeper;\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\n\nimport java.time.Duration;\nimport java.util.Random;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static rx.Observable.just;\n\n@Ignore\npublic class Shakespeare {\n\n\tObservable<String> speak(String quote, long millisPerChar) {\n\t\tString[] tokens = quote.replaceAll(\"[:,]\", \"\").split(\" \");\n\t\tObservable<String> words = Observable.from(tokens);\n\t\tObservable<Long> absoluteDelay = words\n\t\t\t\t.map(String::length)\n\t\t\t\t.map(len -> len * millisPerChar)\n\t\t\t\t.scan((total, current) -> total + current);\n\t\treturn words\n\t\t\t\t.zipWith(absoluteDelay.startWith(0L), Pair::of)\n\t\t\t\t.flatMap(pair -> just(pair.getLeft())\n\t\t\t\t\t\t.delay(pair.getRight(), MILLISECONDS));\n\t}\n\n\t@Test\n\tpublic void sample_28() throws Exception {\n\t\tObservable<String> alice = speak(\n\t\t\t\t\"To be, or not to be: that is the question\", 110);\n\t\tObservable<String> bob = speak(\n\t\t\t\t\"Though this be madness, yet there is method in't\", 90);\n\t\tObservable<String> jane = speak(\n\t\t\t\t\"There are more things in Heaven and Earth, \" +\n\t\t\t\t\t\t\"Horatio, than are dreamt of in your philosophy\", 100);\n\n\t\tObservable\n\t\t\t\t.merge(\n\t\t\t\t\t\talice.map(w -> \"Alice: \" + w),\n\t\t\t\t\t\tbob.map(w   -> \"Bob:   \" + w),\n\t\t\t\t\t\tjane.map(w  -> \"Jane:  \" + w)\n\t\t\t\t)\n\t\t\t\t.subscribe(System.out::println);\n\n\t\tSleeper.sleep(Duration.ofSeconds(10));\n\t}\n\n\t@Test\n\tpublic void sample_52() throws Exception {\n\t\tObservable<String> alice = speak(\n\t\t\t\t\"To be, or not to be: that is the question\", 110);\n\t\tObservable<String> bob = speak(\n\t\t\t\t\"Though this be madness, yet there is method in't\", 90);\n\t\tObservable<String> jane = speak(\n\t\t\t\t\"There are more things in Heaven and Earth, \" +\n\t\t\t\t\t\t\"Horatio, than are dreamt of in your philosophy\", 100);\n\n\t\tRandom rnd = new Random();\n\t\tObservable<Observable<String>> quotes = just(\n\t\t\t\talice.map(w -> \"Alice: \" + w),\n\t\t\t\tbob.map(w   -> \"Bob:   \" + w),\n\t\t\t\tjane.map(w  -> \"Jane:  \" + w))\n\t\t\t\t.flatMap(innerObs -> just(innerObs)\n\t\t\t\t\t\t.delay(rnd.nextInt(5), SECONDS));\n\n\t\tObservable\n\t\t\t\t.switchOnNext(quotes)\n\t\t\t\t.subscribe(System.out::println);\n\t\tSleeper.sleep(Duration.ofSeconds(10));\n\t}\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Sound.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nenum Sound { DI, DAH }\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/User.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport rx.Observable;\n\nclass User {\n    Observable<Profile> loadProfile() {\n        //Make HTTP request...\n        return Observable.just(new Profile());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Vacation.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport rx.Observable;\n\nimport java.time.LocalDate;\n\nclass Vacation {\n\tprivate final City where;\n\tprivate final LocalDate when;\n\n\tVacation(City where, LocalDate when) {\n\t\tthis.where = where;\n\t\tthis.when = when;\n\t}\n\n\tpublic Observable<Weather> weather() {\n\t\t//...\n\t\treturn Observable.just(new Weather(new Temperature(), new Wind()));\n\t}\n\n\tpublic Observable<Flight> cheapFlightFrom(City from) {\n\t\t//...\n\t\treturn Observable.just(new Flight());\n\t}\n\n\tpublic Observable<Hotel> cheapHotel() {\n\t\t//...\n\t\treturn Observable.just(new Hotel());\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/Weather.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nclass Weather {\n    private final Temperature temperature;\n\n    public Weather(Temperature temperature, Wind wind) {\n        //...\n        this.temperature = temperature;\n    }\n\n    public boolean isSunny() {\n        return true;\n    }\n\n    Temperature getTemperature() {\n        return temperature;\n    }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch3/WeatherStation.java",
    "content": "package com.oreilly.rxjava.ch3;\n\nimport rx.Observable;\n\ninterface WeatherStation {\n    Observable<Temperature> temperature();\n    Observable<Wind> wind();\n}\n\nclass BasicWeatherStation implements WeatherStation {\n\n    @Override\n    public Observable<Temperature> temperature() {\n        return Observable.just(new Temperature());\n    }\n\n    @Override\n    public Observable<Wind> wind() {\n        return Observable.just(new Wind());\n    }\n}\n\nclass Temperature {}\n\nclass Wind {}\n\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Book.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass Book {\n\tpublic String getTitle() {\n\t\treturn \"Title\";\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Chapter4.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport com.google.common.util.concurrent.ThreadFactoryBuilder;\nimport com.oreilly.rxjava.util.Sleeper;\nimport org.apache.commons.lang3.RandomUtils;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.observables.BlockingObservable;\nimport rx.schedulers.Schedulers;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.*;\n\n\n@Ignore\npublic class Chapter4 {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Chapter4.class);\n\n\tprivate final PersonDao personDao = new PersonDao();\n\tprivate int orderBookLength;\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tList<Person> people = personDao.listPeople();\n\t\tString json = marshal(people);\n\t}\n\n\t@Test\n\tpublic void sample_20() throws Exception {\n\t\tObservable<Person> peopleStream = personDao.listPeople2();\n\t\tObservable<List<Person>> peopleList = peopleStream.toList();\n\t\tBlockingObservable<List<Person>> peopleBlocking = peopleList.toBlocking();\n\t\tList<Person> people = peopleBlocking.single();\n\t}\n\n\tprivate String marshal(List<Person> people) {\n\t\treturn people.toString();\n\t}\n\n\t@Test\n\tpublic void sample_34() throws Exception {\n\t\tList<Person> people = personDao\n\t\t\t\t.listPeople2()\n\t\t\t\t.toList()\n\t\t\t\t.toBlocking()\n\t\t\t\t.single();\n\t}\n\n\tvoid bestBookFor(Person person) {\n\t\tBook book;\n\t\ttry {\n\t\t\tbook = recommend(person);\n\t\t} catch (Exception e) {\n\t\t\tbook = bestSeller();\n\t\t}\n\t\tdisplay(book.getTitle());\n\t}\n\n\tprivate Book bestSeller() {\n\t\treturn new Book();\n\t}\n\n\tprivate Book recommend(Person person) {\n\t\treturn new Book();\n\t}\n\n\tvoid display(String title) {\n\t\t//...\n\t}\n\n\tvoid bestBookFor2(Person person) {\n\t\tObservable<Book> recommended = recommend2(person);\n\t\tObservable<Book> bestSeller = bestSeller2();\n\t\tObservable<Book> book = recommended.onErrorResumeNext(bestSeller);\n\t\tObservable<String> title = book.map(Book::getTitle);\n\t\ttitle.subscribe(this::display);\n\t}\n\n\tvoid bestBookFor3(Person person) {\n\t\trecommend2(person)\n\t\t\t\t.onErrorResumeNext(bestSeller2())\n\t\t\t\t.map(Book::getTitle)\n\t\t\t\t.subscribe(this::display);\n\t}\n\n\tprivate Observable<Book> bestSeller2() {\n\t\treturn Observable.fromCallable(Book::new);\n\t}\n\n\tprivate Observable<Book> recommend2(Person person) {\n\t\treturn Observable.fromCallable(Book::new);\n\t}\n\n\t@Test\n\tpublic void sample_89() throws Exception {\n\t\tObservable\n\t\t\t\t.interval(10, TimeUnit.MILLISECONDS)\n\t\t\t\t.map(x -> getOrderBookLength())\n\t\t\t\t.distinctUntilChanged();\n\t}\n\n\tprivate int getOrderBookLength() {\n\t\treturn RandomUtils.nextInt(5, 10);\n\t}\n\n\tObservable<Item> observeNewItems() {\n\t\treturn Observable\n\t\t\t\t.interval(1, TimeUnit.SECONDS)\n\t\t\t\t.flatMapIterable(x -> query())\n\t\t\t\t.distinct();\n\t}\n\n\tList<Item> query() {\n\t\t//take snapshot of file system directory\n\t\t//or database table\n\t\treturn Collections.emptyList();\n\t}\n\n\t@Test\n\tpublic void sample_118() throws Exception {\n\t\tThreadFactory threadFactory = new ThreadFactoryBuilder()\n\t\t\t\t.setNameFormat(\"MyPool-%d\")\n\t\t\t\t.build();\n\t\tExecutor executor = new ThreadPoolExecutor(\n\t\t\t\t10,  //corePoolSize\n\t\t\t\t10,  //maximumPoolSize\n\t\t\t\t0L, TimeUnit.MILLISECONDS, //keepAliveTime, unit\n\t\t\t\tnew LinkedBlockingQueue<>(1000),  //workQueue\n\t\t\t\tthreadFactory\n\t\t);\n\t\tScheduler scheduler = Schedulers.from(executor);\n\t}\n\n\t@Test\n\tpublic void sample_136() throws Exception {\n\t\tExecutorService executor = Executors.newFixedThreadPool(10);\n\t}\n\n\tprivate final long start = System.currentTimeMillis();\n\n\tvoid log(Object label) {\n\t\tSystem.out.println(\n\t\t\t\tSystem.currentTimeMillis() - start + \"\\t| \" +\n\t\t\t\t\t\tThread.currentThread().getName()   + \"\\t| \" +\n\t\t\t\t\t\tlabel);\n\t}\n\n\t@Test\n\tpublic void sample_141() throws Exception {\n\t\tScheduler scheduler = Schedulers.immediate();\n\t\tScheduler.Worker worker = scheduler.createWorker();\n\n\t\tlog(\"Main start\");\n\t\tworker.schedule(() -> {\n\t\t\tlog(\" Outer start\");\n\t\t\tsleepOneSecond();\n\t\t\tworker.schedule(() -> {\n\t\t\t\tlog(\"  Inner start\");\n\t\t\t\tsleepOneSecond();\n\t\t\t\tlog(\"  Inner end\");\n\t\t\t});\n\t\t\tlog(\" Outer end\");\n\t\t});\n\t\tlog(\"Main end\");\n\t\tworker.unsubscribe();\n\t}\n\n\t@Test\n\tpublic void sample_175() throws Exception {\n\t\tScheduler scheduler = Schedulers.immediate();\n\t\tScheduler.Worker worker = scheduler.createWorker();\n\n\t\tlog(\"Main start\");\n\t\tworker.schedule(() -> {\n\t\t\tlog(\" Outer start\");\n\t\t\tsleepOneSecond();\n\t\t\tworker.schedule(() -> {\n\t\t\t\tlog(\"  Middle start\");\n\t\t\t\tsleepOneSecond();\n\t\t\t\tworker.schedule(() -> {\n\t\t\t\t\tlog(\"   Inner start\");\n\t\t\t\t\tsleepOneSecond();\n\t\t\t\t\tlog(\"   Inner end\");\n\t\t\t\t});\n\t\t\t\tlog(\"  Middle end\");\n\t\t\t});\n\t\t\tlog(\" Outer end\");\n\t\t});\n\t\tlog(\"Main end\");\n\t}\n\n\tprivate void sleepOneSecond() {\n\t\tSleeper.sleep(Duration.ofSeconds(1));\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Flight.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass Flight {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Flights.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.schedulers.Schedulers;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Stream;\n\nimport static java.util.stream.Collectors.toList;\nimport static rx.Observable.fromCallable;\n\n@Ignore\npublic class Flights {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Flights.class);\n\n\tFlight lookupFlight(String flightNo) {\n\t\t//...\n\t\treturn new Flight();\n\t}\n\n\tPassenger findPassenger(long id) {\n\t\t//...\n\t\treturn new Passenger();\n\t}\n\n\tTicket bookTicket(Flight flight, Passenger passenger) {\n\t\t//...\n\t\treturn new Ticket();\n\t}\n\n\tSmtpResponse sendEmail(Ticket ticket) {\n\t\t//...\n\t\treturn new SmtpResponse();\n\t}\n\n\t@Test\n\tpublic void sample_29() throws Exception {\n\t\tFlight flight = lookupFlight(\"LOT 783\");\n\t\tPassenger passenger = findPassenger(42);\n\t\tTicket ticket = bookTicket(flight, passenger);\n\t\tsendEmail(ticket);\n\t}\n\n\tObservable<Flight> rxLookupFlight(String flightNo) {\n\t\treturn Observable.defer(() ->\n\t\t\t\tObservable.just(lookupFlight(flightNo)));\n\t}\n\n\tObservable<Passenger> rxFindPassenger(long id) {\n\t\treturn Observable.defer(() ->\n\t\t\t\tObservable.just(findPassenger(id)));\n\t}\n\n\t@Test\n\tpublic void sample_49() throws Exception {\n\t\tObservable<Flight> flight = rxLookupFlight(\"LOT 783\");\n\t\tObservable<Passenger> passenger = rxFindPassenger(42);\n\t\tObservable<Ticket> ticket =\n\t\t\t\tflight.zipWith(passenger, (f, p) -> bookTicket(f, p));\n\t\tticket.subscribe(this::sendEmail);\n\t}\n\n\t@Test\n\tpublic void sample_67() throws Exception {\n\t\trxLookupFlight(\"LOT 783\")\n\t\t\t\t.subscribeOn(Schedulers.io())\n\t\t\t\t.timeout(100, TimeUnit.MILLISECONDS);\n\t}\n\n\t@Test\n\tpublic void sample_76() throws Exception {\n\t\tObservable<Flight> flight =\n\t\t\t\trxLookupFlight(\"LOT 783\").subscribeOn(Schedulers.io());\n\t\tObservable<Passenger> passenger =\n\t\t\t\trxFindPassenger(42).subscribeOn(Schedulers.io());\n\n\t\tObservable<Ticket> ticket = flight\n\t\t\t\t.zipWith(passenger, (Flight f, Passenger p) -> Pair.of(f, p))\n\t\t\t\t.flatMap(pair -> rxBookTicket(pair.getLeft(), pair.getRight()));\n\t}\n\n\tprivate Observable<Ticket> rxBookTicket(Flight left, Passenger right) {\n\t\treturn Observable.just(new Ticket());\n\t}\n\n\t@Test\n\tpublic void sample_85() throws Exception {\n\t\tObservable<Flight> flight =\n\t\t\t\trxLookupFlight(\"LOT 783\").subscribeOn(Schedulers.io());\n\t\tObservable<Passenger> passenger =\n\t\t\t\trxFindPassenger(42).subscribeOn(Schedulers.io());\n\n\t\tObservable<Ticket> ticket = flight\n\t\t\t\t.zipWith(passenger, this::rxBookTicket)\n\t\t\t\t.flatMap(obs -> obs);\n\t}\n\n\t@Test\n\tpublic void sample_97() throws Exception {\n\t\tList<Ticket> tickets = Arrays.asList(new Ticket(), new Ticket(), new Ticket());\n\t\tList<Ticket> failures = new ArrayList<>();\n\t\tfor (Ticket ticket : tickets) {\n\t\t\ttry {\n\t\t\t\tsendEmail(ticket);\n\t\t\t} catch (Exception e) {\n\t\t\t\tlog.warn(\"Failed to send {}\", ticket, e);\n\t\t\t\tfailures.add(ticket);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tpublic void sample_120() throws Exception {\n\t\tList<Ticket> tickets = Arrays.asList(new Ticket(), new Ticket(), new Ticket());\n\n\t\tList<Pair<Ticket, Future<SmtpResponse>>> tasks = tickets\n\t\t\t\t.stream()\n\t\t\t\t.map(ticket -> Pair.of(ticket, sendEmailAsync(ticket)))\n\t\t\t\t.collect(toList());\n\n\t\tList<Ticket> failures = tasks.stream()\n\t\t\t\t.flatMap(pair -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tFuture<SmtpResponse> future = pair.getRight();\n\t\t\t\t\t\tfuture.get(1, TimeUnit.SECONDS);\n\t\t\t\t\t\treturn Stream.empty();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tTicket ticket = pair.getLeft();\n\t\t\t\t\t\tlog.warn(\"Failed to send {}\", ticket, e);\n\t\t\t\t\t\treturn Stream.of(ticket);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.collect(toList());\n\t}\n\n\tprivate Future<SmtpResponse> sendEmailAsync(Ticket ticket) {\n\t\treturn CompletableFuture.supplyAsync(() -> sendEmail(ticket));\n\t}\n\n\t@Test\n\tpublic void sample_152() throws Exception {\n\t\tList<Ticket> tickets = Arrays.asList(new Ticket(), new Ticket(), new Ticket());\n\n\t\t//WARNING: code is sequential despite utilizing thread pool\n\t\ttickets\n\t\t\t\t.stream()\n\t\t\t\t.map(ticket -> Pair.of(ticket, sendEmailAsync(ticket)))\n\t\t\t\t.map(pair -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn pair.getRight().get();\n\t\t\t\t\t} catch (InterruptedException | ExecutionException e) {\n\t\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.collect(toList());\n\t}\n\n\tObservable<SmtpResponse> rxSendEmail(Ticket ticket) {\n\t\t//unusual synchronous Observable\n\t\treturn fromCallable(() -> sendEmail(ticket));\n\t}\n\n\t@Test\n\tpublic void sample_177() throws Exception {\n\t\tList<Ticket> tickets = Arrays.asList(new Ticket(), new Ticket(), new Ticket());\n\t\tList<Ticket> failures = Observable.from(tickets)\n\t\t\t\t.flatMap(ticket ->\n\t\t\t\t\t\trxSendEmail(ticket)\n\t\t\t\t\t\t\t\t.flatMap(response -> Observable.<Ticket>empty())\n\t\t\t\t\t\t\t\t.doOnError(e -> log.warn(\"Failed to send {}\", ticket, e))\n\t\t\t\t\t\t\t\t.onErrorReturn(err -> ticket))\n\t\t\t\t.toList()\n\t\t\t\t.toBlocking()\n\t\t\t\t.single();\n\t}\n\n\t@Test\n\tpublic void sample_191() throws Exception {\n\t\tList<Ticket> tickets = Arrays.asList(new Ticket(), new Ticket(), new Ticket());\n\n\t\tObservable\n\t\t\t\t.from(tickets)\n\t\t\t\t.flatMap(ticket ->\n\t\t\t\t\t\trxSendEmail(ticket)\n\t\t\t\t\t\t\t\t.ignoreElements()\n\t\t\t\t\t\t\t\t.doOnError(e -> log.warn(\"Failed to send {}\", ticket, e))\n\t\t\t\t\t\t\t\t.subscribeOn(Schedulers.io()));\n\t}\n\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Item.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass Item {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/JmsConsumer.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.messaging.Message;\nimport org.springframework.stereotype.Component;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\n\n@Component\nclass JmsConsumer {\n\n    private final PublishSubject<Message> subject = PublishSubject.create();\n\n    @JmsListener(destination = \"orders\", concurrency=\"1\")\n    public void newOrder(Message msg) {\n        subject.onNext(msg);\n    }\n\n    Observable<Message> observe() {\n        return subject;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Messaging.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.apache.activemq.command.ActiveMQTopic;\nimport org.junit.Ignore;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.subscriptions.Subscriptions;\n\nimport javax.jms.*;\n\nimport static javax.jms.Session.AUTO_ACKNOWLEDGE;\n\n@Ignore\npublic class Messaging {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Messaging.class);\n\n\tvoid connect() {\n\t\tConnectionFactory connectionFactory = new ActiveMQConnectionFactory(\"tcp://localhost:61616\");\n\t\tObservable<String> txtMessages = observe(connectionFactory, new ActiveMQTopic(\"orders\"))\n\t\t\t\t.cast(TextMessage.class)\n\t\t\t\t.flatMap(m -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn Observable.just(m.getText());\n\t\t\t\t\t} catch (JMSException e) {\n\t\t\t\t\t\treturn Observable.error(e);\n\t\t\t\t\t}\n\t\t\t\t});\n\t}\n\n\tpublic Observable<Message> observe(ConnectionFactory connectionFactory, Topic topic) {\n\t\treturn Observable.create(subscriber -> {\n\t\t\ttry {\n\t\t\t\tsubscribeThrowing(subscriber, connectionFactory, topic);\n\t\t\t} catch (JMSException e) {\n\t\t\t\tsubscriber.onError(e);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void subscribeThrowing(Subscriber<? super Message> subscriber, ConnectionFactory connectionFactory, Topic orders) throws JMSException {\n\t\tConnection connection = connectionFactory.createConnection();\n\t\tSession session = connection.createSession(true, AUTO_ACKNOWLEDGE);\n\t\tMessageConsumer consumer = session.createConsumer(orders);\n\t\tconsumer.setMessageListener(subscriber::onNext);\n\t\tsubscriber.add(onUnsubscribe(connection));\n\t\tconnection.start();\n\t}\n\n\tprivate Subscription onUnsubscribe(Connection connection) {\n\t\treturn Subscriptions.create(() -> {\n\t\t\ttry {\n\t\t\t\tconnection.close();\n\t\t\t} catch (Exception e) {\n\t\t\t\tlog.error(\"Can't close\", e);\n\t\t\t}\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Passenger.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass Passenger {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Person.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass Person {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/PersonDao.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport rx.Observable;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static rx.Observable.defer;\nimport static rx.Observable.from;\n\nclass PersonDao {\n\n    private static final int PAGE_SIZE = 10;\n\n    Observable<Person> allPeople(int initialPage) {\n        return defer(() -> from(listPeople(initialPage)))\n                .concatWith(defer(() ->\n                        allPeople(initialPage + 1)));\n    }\n\n    void allPeople() {\n        Observable<Person> allPages = Observable\n                .range(0, Integer.MAX_VALUE)\n                .map(this::listPeople)\n                .takeWhile(list -> !list.isEmpty())\n                .concatMap(Observable::from);\n    }\n\n    List<Person> listPeople() {\n        return query(\"SELECT * FROM PEOPLE\");\n    }\n\n    List<Person> listPeople(int initialPage) {\n        return query(\"SELECT * FROM PEOPLE OFFSET ? MAX ?\", initialPage * 10, PAGE_SIZE);\n    }\n\n    Observable<Person> listPeople2() {\n        final List<Person> people = query(\"SELECT * FROM PEOPLE\");\n        return Observable.from(people);\n    }\n\n    public Observable<Person> listPeople3() {\n        return defer(() ->\n                Observable.from(query(\"SELECT * FROM PEOPLE\")));\n    }\n\n    private List<Person> query(String sql, Object... args) {\n        //...\n        return Arrays.asList(new Person(), new Person());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/RxGroceries.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\n\nimport java.math.BigDecimal;\n\nclass RxGroceries {\n\n    private static final Logger log = LoggerFactory.getLogger(RxGroceries.class);\n\n    private final long start = System.currentTimeMillis();\n\n    void log(Object label) {\n        System.out.println(\n                System.currentTimeMillis() - start + \"\\t| \" +\n                        Thread.currentThread().getName()   + \"\\t| \" +\n                        label);\n    }\n\n\n    Observable<BigDecimal> purchase(String productName, int quantity) {\n        return Observable.fromCallable(() ->\n            doPurchase(productName, quantity));\n    }\n\n    BigDecimal doPurchase(String productName, int quantity) {\n        log(\"Purchasing \" + quantity + \" \" + productName);\n        //real logic here\n        log(\"Done \" + quantity + \" \" + productName);\n        BigDecimal priceForProduct = BigDecimal.ONE;\n        return priceForProduct;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Schedulers.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport com.google.common.util.concurrent.ThreadFactoryBuilder;\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Scheduler;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadFactory;\n\nimport static java.util.concurrent.Executors.newFixedThreadPool;\nimport static java.util.concurrent.TimeUnit.SECONDS;\n\n@Ignore\npublic class Schedulers {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Schedulers.class);\n\n\tExecutorService poolA = newFixedThreadPool(10, threadFactory(\"Sched-A-%d\"));\n\tScheduler schedulerA = rx.schedulers.Schedulers.from(poolA);\n\n\tExecutorService poolB = newFixedThreadPool(10, threadFactory(\"Sched-B-%d\"));\n\tScheduler schedulerB = rx.schedulers.Schedulers.from(poolB);\n\n\tExecutorService poolC = newFixedThreadPool(10, threadFactory(\"Sched-C-%d\"));\n\tScheduler schedulerC = rx.schedulers.Schedulers.from(poolC);\n\n\tprivate final long start = System.currentTimeMillis();\n\n\tvoid log(Object label) {\n\t\tSystem.out.println(\n\t\t\t\tSystem.currentTimeMillis() - start + \"\\t| \" +\n\t\t\t\t\t\tThread.currentThread().getName()   + \"\\t| \" +\n\t\t\t\t\t\tlabel);\n\t}\n\n\tprivate ThreadFactory threadFactory(String pattern) {\n\t\treturn new ThreadFactoryBuilder()\n\t\t\t\t.setNameFormat(pattern)\n\t\t\t\t.build();\n\t}\n\n\tObservable<String> simple() {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tlog(\"Subscribed\");\n\t\t\tsubscriber.onNext(\"A\");\n\t\t\tsubscriber.onNext(\"B\");\n\t\t\tsubscriber.onCompleted();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_215() throws Exception {\n\t\tlog(\"Starting\");\n\t\tfinal Observable<String> obs = simple();\n\t\tlog(\"Created\");\n\t\tobs\n\t\t\t\t.subscribeOn(schedulerA)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tx -> log(\"Got \" + x),\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> log(\"Completed\")\n\t\t\t\t);\n\t\tlog(\"Exiting\");\n\t}\n\n\n\t@Test\n\tpublic void sample_33() throws Exception {\n\t\t//Don't do this\n\t\tObservable<String> obs = Observable.create(subscriber -> {\n\t\t\tlog(\"Subscribed\");\n\t\t\tRunnable code = () -> {\n\t\t\t\tsubscriber.onNext(\"A\");\n\t\t\t\tsubscriber.onNext(\"B\");\n\t\t\t\tsubscriber.onCompleted();\n\t\t\t};\n\t\t\tnew Thread(code, \"Async\").start();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_77() throws Exception {\n\t\tlog(\"Starting\");\n\t\tObservable<String> obs = simple();\n\t\tlog(\"Created\");\n\t\tobs\n\t\t\t\t.subscribeOn(schedulerA)\n\t\t\t\t//many other operators\n\t\t\t\t.subscribeOn(schedulerB)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tx -> log(\"Got \" + x),\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> log(\"Completed\")\n\t\t\t\t);\n\t\tlog(\"Exiting\");\n\t}\n\n\t@Test\n\tpublic void sample_103() throws Exception {\n\t\tlog(\"Starting\");\n\t\tfinal Observable<String> obs = simple();\n\t\tlog(\"Created\");\n\t\tobs\n\t\t\t\t.doOnNext(this::log)\n\t\t\t\t.map(x -> x + '1')\n\t\t\t\t.doOnNext(this::log)\n\t\t\t\t.map(x -> x + '2')\n\t\t\t\t.subscribeOn(schedulerA)\n\t\t\t\t.doOnNext(this::log)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tx -> log(\"Got \" + x),\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> log(\"Completed\")\n\t\t\t\t);\n\t\tlog(\"Exiting\");\n\t}\n\n\tprivate final RxGroceries rxGroceries = new RxGroceries();\n\n\t@Test\n\tpublic void sample_122() throws Exception {\n\t\tObservable<BigDecimal> totalPrice = Observable\n\t\t\t\t.just(\"bread\", \"butter\", \"milk\", \"tomato\", \"cheese\")\n\t\t\t\t.subscribeOn(schedulerA)  //BROKEN!!!\n\t\t\t\t.map(prod -> rxGroceries.doPurchase(prod, 1))\n\t\t\t\t.reduce(BigDecimal::add)\n\t\t\t\t.single();\n\t}\n\n\t@Test\n\tpublic void sample_135() throws Exception {\n\t\tfinal Observable<BigDecimal> totalPrice = Observable\n\t\t\t\t.just(\"bread\", \"butter\", \"milk\", \"tomato\", \"cheese\")\n\t\t\t\t.subscribeOn(schedulerA)\n\t\t\t\t.flatMap(prod -> rxGroceries.purchase(prod, 1))\n\t\t\t\t.reduce(BigDecimal::add)\n\t\t\t\t.single();\n\t}\n\n\t@Test\n\tpublic void sample_145() throws Exception {\n\t\tObservable<BigDecimal> totalPrice = Observable\n\t\t\t\t.just(\"bread\", \"butter\", \"milk\", \"tomato\", \"cheese\")\n\t\t\t\t.flatMap(prod ->\n\t\t\t\t\t\trxGroceries\n\t\t\t\t\t\t\t\t.purchase(prod, 1)\n\t\t\t\t\t\t\t\t.subscribeOn(schedulerA))\n\t\t\t\t.reduce(BigDecimal::add)\n\t\t\t\t.single();\n\t}\n\n\t@Test\n\tpublic void sample_157() throws Exception {\n\t\tObservable<BigDecimal> totalPrice = Observable\n\t\t\t\t.just(\"bread\", \"butter\", \"egg\", \"milk\", \"tomato\",\n\t\t\t\t\t\t\"cheese\", \"tomato\", \"egg\", \"egg\")\n\t\t\t\t.groupBy(prod -> prod)\n\t\t\t\t.flatMap(grouped -> grouped\n\t\t\t\t\t\t.count()\n\t\t\t\t\t\t.map(quantity -> {\n\t\t\t\t\t\t\tString productName = grouped.getKey();\n\t\t\t\t\t\t\treturn Pair.of(productName, quantity);\n\t\t\t\t\t\t}))\n\t\t\t\t.flatMap(order -> rxGroceries\n\t\t\t\t\t\t.purchase(order.getKey(), order.getValue())\n\t\t\t\t\t\t.subscribeOn(schedulerA))\n\t\t\t\t.reduce(BigDecimal::add)\n\t\t\t\t.single();\n\t}\n\n\t@Test\n\tpublic void sample_177() throws Exception {\n\t\tlog(\"Starting\");\n\t\tfinal Observable<String> obs = simple();\n\t\tlog(\"Created\");\n\t\tobs\n\t\t\t\t.doOnNext(x -> log(\"Found 1: \" + x))\n\t\t\t\t.observeOn(schedulerA)\n\t\t\t\t.doOnNext(x -> log(\"Found 2: \" + x))\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tx -> log(\"Got 1: \" + x),\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> log(\"Completed\")\n\t\t\t\t);\n\t\tlog(\"Exiting\");\n\t}\n\n\t@Test\n\tpublic void sample_194() throws Exception {\n\t\tlog(\"Starting\");\n\t\tfinal Observable<String> obs = simple();\n\t\tlog(\"Created\");\n\t\tobs\n\t\t\t\t.doOnNext(x -> log(\"Found 1: \" + x))\n\t\t\t\t.observeOn(schedulerB)\n\t\t\t\t.doOnNext(x -> log(\"Found 2: \" + x))\n\t\t\t\t.observeOn(schedulerC)\n\t\t\t\t.doOnNext(x -> log(\"Found 3: \" + x))\n\t\t\t\t.subscribeOn(schedulerA)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tx -> log(\"Got 1: \" + x),\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> log(\"Completed\")\n\t\t\t\t);\n\t\tlog(\"Exiting\");\n\t}\n\n\t@Test\n\tpublic void sample_214() throws Exception {\n\t\tlog(\"Starting\");\n\t\tObservable<String> obs = Observable.create(subscriber -> {\n\t\t\tlog(\"Subscribed\");\n\t\t\tsubscriber.onNext(\"A\");\n\t\t\tsubscriber.onNext(\"B\");\n\t\t\tsubscriber.onNext(\"C\");\n\t\t\tsubscriber.onNext(\"D\");\n\t\t\tsubscriber.onCompleted();\n\t\t});\n\t\tlog(\"Created\");\n\t\tobs\n\t\t\t\t.subscribeOn(schedulerA)\n\t\t\t\t.flatMap(record -> store(record).subscribeOn(schedulerB))\n\t\t\t\t.observeOn(schedulerC)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tx -> log(\"Got: \" + x),\n\t\t\t\t\t\tThrowable::printStackTrace,\n\t\t\t\t\t\t() -> log(\"Completed\")\n\t\t\t\t);\n\t\tlog(\"Exiting\");\n\t}\n\n\tObservable<UUID> store(String s) {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tlog(\"Storing \" + s);\n\t\t\t//hard work\n\t\t\tsubscriber.onNext(UUID.randomUUID());\n\t\t\tsubscriber.onCompleted();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_248() throws Exception {\n\t\tObservable\n\t\t\t\t.just('A', 'B')\n\t\t\t\t.delay(1, SECONDS, schedulerA)\n\t\t\t\t.subscribe(this::log);\n\t}\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/SimplifiedHandlerScheduler.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nimport android.os.Handler;\nimport android.os.Looper;\nimport rx.Scheduler;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.internal.schedulers.ScheduledAction;\nimport rx.subscriptions.CompositeSubscription;\nimport rx.subscriptions.Subscriptions;\n\nimport java.util.concurrent.TimeUnit;\n\npublic final class SimplifiedHandlerScheduler extends Scheduler {\n\n    @Override\n    public Worker createWorker() {\n        return new HandlerWorker();\n    }\n\n    static class HandlerWorker extends Worker {\n\n        private final Handler handler = new Handler(Looper.getMainLooper());\n\n        @Override\n        public Subscription schedule(final Action0 action) {\n            return schedule(action, 0, TimeUnit.MILLISECONDS);\n        }\n\n        private final CompositeSubscription compositeSubscription = new CompositeSubscription();\n\n        @Override\n        public void unsubscribe() {\n            compositeSubscription.unsubscribe();\n        }\n\n        @Override\n        public boolean isUnsubscribed() {\n            return compositeSubscription.isUnsubscribed();\n        }\n\n        @Override\n        public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {\n            if (compositeSubscription.isUnsubscribed()) {\n                return Subscriptions.unsubscribed();\n            }\n\n            final ScheduledAction scheduledAction = new ScheduledAction(action);\n            scheduledAction.addParent(compositeSubscription);\n            compositeSubscription.add(scheduledAction);\n\n            handler.postDelayed(scheduledAction, unit.toMillis(delayTime));\n\n            scheduledAction.add(Subscriptions.create(() ->\n                    handler.removeCallbacks(scheduledAction)));\n\n            return scheduledAction;\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/SmtpResponse.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass SmtpResponse {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch4/Ticket.java",
    "content": "package com.oreilly.rxjava.ch4;\n\nclass Ticket {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/Chapter5.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.netty.buffer.ByteBuf;\nimport io.reactivex.netty.protocol.http.client.HttpClient;\nimport io.reactivex.netty.protocol.http.client.HttpClientResponse;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\n\nimport java.net.URL;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\n@Ignore\npublic class Chapter5 {\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tObservable<ByteBuf> response = HttpClient\n\t\t\t\t.newClient(\"example.com\", 80)\n\t\t\t\t.createGet(\"/\")\n\t\t\t\t.flatMap(HttpClientResponse::getContent);\n\t\tresponse\n\t\t\t\t.map(bb -> bb.toString(UTF_8))\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_22() throws Exception {\n\t\tObservable<URL> sources = Observable.just(new URL(\"http://www.google.com\"));\n\n\t\tObservable<ByteBuf> packets =\n\t\t\t\tsources\n\t\t\t\t\t\t.flatMap(url -> HttpClient\n\t\t\t\t\t\t\t\t.newClient(url.getHost(), url.getPort())\n\t\t\t\t\t\t\t\t.createGet(url.getPath()))\n\t\t\t\t\t\t.flatMap(HttpClientResponse::getContent);\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/CompletableFutures.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\n\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.*;\n\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static java.util.function.UnaryOperator.identity;\n\n@Ignore\npublic class CompletableFutures {\n\n\tUser findById(long id) {\n\t\treturn new User();\n\t}\n\n\tGeoLocation locate() {\n\t\treturn new GeoLocation();\n\t}\n\n\tTicket book(Flight flight) {\n\t\treturn new Ticket();\n\t}\n\n\t@Test\n\tpublic void sample_21() throws Exception {\n\t\tlong id = 42;\n\n\t\tExecutorService pool = Executors.newFixedThreadPool(10);\n\t\tList<TravelAgency> agencies = Collections.singletonList(new SomeTravelAgency());\n\n\t\tUser user = findById(id);\n\t\tGeoLocation location = locate();\n\t\tExecutorCompletionService<Flight> ecs = new ExecutorCompletionService<>(pool);\n\t\tagencies.forEach(agency ->\n\t\t\t\tecs.submit(() ->\n\t\t\t\t\t\tagency.search(user, location)));\n\t\tFuture<Flight> firstFlight = ecs.poll(5, SECONDS);\n\t\tFlight flight = firstFlight.get();\n\t\tbook(flight);\n\t}\n\n\tCompletableFuture<User> findByIdAsync(long id) {\n\t\treturn CompletableFuture.supplyAsync(() -> findById(id));\n\t}\n\n\tCompletableFuture<GeoLocation> locateAsync() {\n\t\treturn CompletableFuture.supplyAsync(this::locate);\n\t}\n\n\tCompletableFuture<Ticket> bookAsync(Flight flight) {\n\t\treturn CompletableFuture.supplyAsync(() -> book(flight));\n\t}\n\n\tObservable<User> rxFindById(long id) {\n\t\treturn Util.observe(findByIdAsync(id));\n\t}\n\n\tObservable<GeoLocation> rxLocate() {\n\t\treturn Util.observe(locateAsync());\n\t}\n\n\tObservable<Ticket> rxBook(Flight flight) {\n\t\treturn Util.observe(bookAsync(flight));\n\t}\n\n\t@Test\n\tpublic void sample_63() throws Exception {\n\t\tlong id = 42;\n\t\tList<TravelAgency> agencies = Collections.singletonList(new SomeTravelAgency());\n\t\tCompletableFuture<User> user = findByIdAsync(id);\n\t\tCompletableFuture<GeoLocation> location = locateAsync();\n\n\t\tCompletableFuture<Ticket> ticketFuture = user\n\t\t\t\t.thenCombine(location, (User us, GeoLocation loc) -> agencies\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.map(agency -> agency.searchAsync(us, loc))\n\t\t\t\t\t\t.reduce((f1, f2) ->\n\t\t\t\t\t\t\t\tf1.applyToEither(f2, identity())\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.get()\n\t\t\t\t)\n\t\t\t\t.thenCompose(identity())\n\t\t\t\t.thenCompose(this::bookAsync);\n\t}\n\n\t@Test\n\tpublic void sample_80() throws Exception {\n\t\tCompletableFuture<Long> timeFuture = CompletableFuture.completedFuture(System.currentTimeMillis());\n\t\tCompletableFuture<ZoneId> zoneFuture = CompletableFuture.completedFuture(ZoneId.of(\"GMT\"));\n\n\t\tCompletableFuture<Instant> instantFuture = timeFuture\n\t\t\t\t.thenApply(time -> Instant.ofEpochMilli(time));\n\n\t\tCompletableFuture<ZonedDateTime> zdtFuture = instantFuture\n\t\t\t\t.thenCombine(zoneFuture, (instant, zoneId) ->\n\t\t\t\t\t\tZonedDateTime.ofInstant(instant, zoneId));\n\t}\n\n\t@Test\n\tpublic void sample_96() throws Exception {\n\t\tList<TravelAgency> agencies = Collections.singletonList(new SomeTravelAgency());\n\n\t\tUser us = new User();\n\t\tGeoLocation loc = new GeoLocation();\n\t\tagencies\n\t\t\t\t.stream()\n\t\t\t\t.map(agency -> agency.searchAsync(us, loc))\n\t\t\t\t.reduce((f1, f2) ->\n\t\t\t\t\t\tf1.applyToEither(f2, identity())\n\t\t\t\t)\n\t\t\t\t.get();\n\n\t}\n\n\t@Test\n\tpublic void sample_111() throws Exception {\n\t\tCompletableFuture<User> primaryFuture = CompletableFuture.completedFuture(new User());\n\t\tCompletableFuture<User> secondaryFuture = CompletableFuture.completedFuture(new User());\n\n\t\tCompletableFuture<LocalDate> ageFuture =\n\t\t\t\tprimaryFuture\n\t\t\t\t\t\t.applyToEither(secondaryFuture,\n\t\t\t\t\t\t\t\tuser -> user.getBirth());\n\t}\n\n\t@Test\n\tpublic void sample_123() throws Exception {\n\t\tCompletableFuture<Flight> flightFuture = CompletableFuture.completedFuture(new Flight());\n\n\t\tCompletableFuture<Ticket> ticketFuture = flightFuture\n\t\t\t\t.thenCompose(flight -> bookAsync(flight));\n\n\t}\n\n\t@Test\n\tpublic void sample_145() throws Exception {\n\t\tlong id = 42;\n\n\t\tObservable<TravelAgency> agencies = agencies();\n\t\tObservable<User> user = rxFindById(id);\n\t\tObservable<GeoLocation> location = rxLocate();\n\n\t\tObservable<Ticket> ticket = user\n\t\t\t\t.zipWith(location, (us, loc) ->\n\t\t\t\t\t\tagencies\n\t\t\t\t\t\t\t\t.flatMap(agency -> agency.rxSearch(us, loc))\n\t\t\t\t\t\t\t\t.first()\n\t\t\t\t)\n\t\t\t\t.flatMap(x -> x)\n\t\t\t\t.flatMap(this::rxBook);\n\n\t}\n\n\tprivate Observable<TravelAgency> agencies() {\n\t\treturn Observable.just(new SomeTravelAgency());\n\t}\n\n\t@Test\n\tpublic void sample_168() throws Exception {\n\t\tObservable<User> user = Observable.just(new User());\n\t\tObservable<GeoLocation> location = Observable.just(new GeoLocation());\n\t\tObservable<TravelAgency> agencies = agencies();\n\n\t\tObservable<Ticket> ticket = user\n\t\t\t\t.zipWith(location, (usr, loc) -> Pair.of(usr, loc))\n\t\t\t\t.flatMap(pair -> agencies\n\t\t\t\t\t\t.flatMap(agency -> {\n\t\t\t\t\t\t\tUser usr = pair.getLeft();\n\t\t\t\t\t\t\tGeoLocation loc = pair.getRight();\n\t\t\t\t\t\t\treturn agency.rxSearch(usr, loc);\n\t\t\t\t\t\t}))\n\t\t\t\t.first()\n\t\t\t\t.flatMap(this::rxBook);\n\n\t}\n\n}\n\n\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/EurUsdCurrencyTcpServer.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.netty.handler.codec.LineBasedFrameDecoder;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.reactivex.netty.protocol.tcp.server.TcpServer;\nimport rx.Observable;\n\nimport java.math.BigDecimal;\nimport java.util.concurrent.TimeUnit;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\nclass EurUsdCurrencyTcpServer {\n\n    private static final BigDecimal RATE = new BigDecimal(\"1.06448\");\n    \n    public static void main(final String[] args) {\n        TcpServer\n            .newServer(8080)\n            .<String, String>pipelineConfigurator(pipeline -> {\n                pipeline.addLast(new LineBasedFrameDecoder(1024));\n                pipeline.addLast(new StringDecoder(UTF_8));\n            })\n            .start(connection -> {\n                Observable<String> output = connection\n                    .getInput()\n                    .map(BigDecimal::new)\n                    .flatMap(eur -> eurToUsd(eur));\n                return connection.writeAndFlushOnEach(output);\n            })\n            .awaitShutdown();\n    }\n\n    static Observable<String> eurToUsd(BigDecimal eur) {\n        return Observable\n            .just(eur.multiply(RATE))\n            .map(amount -> eur + \" EUR is \" + amount + \" USD\\n\")\n            .delay(1, TimeUnit.SECONDS);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/Flight.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nclass Flight {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/GeoLocation.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nclass GeoLocation {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/HttpHandler.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.DefaultFullHttpResponse;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\n@ChannelHandler.Sharable\nclass HttpHandler extends ChannelInboundHandlerAdapter {\n\n    private static final Logger log = LoggerFactory.getLogger(HttpHandler.class);\n\n    @Override\n    public void channelReadComplete(ChannelHandlerContext ctx) {\n        ctx.flush();\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) {\n        if (msg instanceof HttpRequest) {\n            sendResponse(ctx);\n        }\n    }\n\n    private void sendResponse(ChannelHandlerContext ctx) {\n        final DefaultFullHttpResponse response = new DefaultFullHttpResponse(\n                HTTP_1_1,\n                HttpResponseStatus.OK,\n                Unpooled.wrappedBuffer(\"OK\".getBytes(UTF_8)));\n        response.headers().add(\"Content-length\", 2);\n        ctx.writeAndFlush(response);\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        log.error(\"Error\", cause);\n        ctx.close();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/HttpInitializer.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.http.HttpServerCodec;\n\n\nclass HttpInitializer extends ChannelInitializer<SocketChannel> {\n\n    private final HttpHandler httpHandler = new HttpHandler();\n\n    @Override\n    public void initChannel(SocketChannel ch) {\n        ch\n                .pipeline()\n                .addLast(new HttpServerCodec())\n                .addLast(httpHandler);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/HttpTcpNettyServer.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\n\nclass HttpTcpNettyServer {\n\n    public static void main(String[] args) throws Exception {\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            new ServerBootstrap()\n                    .option(ChannelOption.SO_BACKLOG, 50_000)\n                    .group(bossGroup, workerGroup)\n                    .channel(NioServerSocketChannel.class)\n                    .childHandler(new HttpInitializer())\n                    .bind(8080)\n                    .sync()\n                    .channel()\n                    .closeFuture()\n                    .sync();\n        } finally {\n            bossGroup.shutdownGracefully();\n            workerGroup.shutdownGracefully();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/HttpTcpRxNettyServer.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.netty.handler.codec.LineBasedFrameDecoder;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.reactivex.netty.protocol.tcp.server.TcpServer;\nimport rx.Observable;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\nclass HttpTcpRxNettyServer {\n\n    public static final Observable<String> RESPONSE = Observable.just(\n            \"HTTP/1.1 200 OK\\r\\n\" +\n            \"Content-length: 2\\r\\n\" +\n            \"\\r\\n\" +\n            \"OK\");\n\n    public static void main(final String[] args) {\n        TcpServer\n            .newServer(8080)\n            .<String, String>pipelineConfigurator(pipeline -> {\n                pipeline.addLast(new LineBasedFrameDecoder(128));\n                pipeline.addLast(new StringDecoder(UTF_8));\n            })\n            .start(connection -> {\n                Observable<String> output = connection\n                    .getInput()\n                    .flatMap(line -> {\n                        if (line.isEmpty()) {\n                            return RESPONSE;\n                        } else {\n                            return Observable.empty();\n                        }\n                    });\n                return connection.writeAndFlushOnEach(output);\n            })\n            .awaitShutdown();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/Postgres.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.postgresql.PGNotification;\nimport org.postgresql.jdbc2.AbstractJdbc2Connection;\nimport org.postgresql.jdbc42.Jdbc42Connection;\nimport rx.Observable;\nimport rx.observers.Subscribers;\nimport rx.subscriptions.Subscriptions;\n\nimport java.sql.*;\nimport java.util.Arrays;\nimport java.util.concurrent.TimeUnit;\n\n@Ignore\npublic class Postgres {\n\n\n\t@Test\n\tpublic void sample_37() throws Exception {\n\t\ttry (\n\t\t\t\tConnection conn = DriverManager.getConnection(\"jdbc:h2:mem:\");\n\t\t\t\tStatement stat = conn.createStatement();\n\t\t\t\tResultSet rs = stat.executeQuery(\"SELECT 2 + 2 AS total\")\n\t\t) {\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(rs.getInt(\"total\"));\n\t\t\t\tassert rs.getInt(\"total\") == 4;\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tpublic void sample_55() throws Exception {\n\t\ttry (Connection connection =\n\t\t\t\t     DriverManager.getConnection(\"jdbc:postgresql:db\")) {\n\t\t\ttry (Statement statement = connection.createStatement()) {\n\t\t\t\tstatement.execute(\"LISTEN my_channel\");\n\t\t\t}\n\t\t\tJdbc42Connection pgConn = (Jdbc42Connection) connection;\n\t\t\tpollForNotifications(pgConn);\n\t\t}\n\t}\n\n\tvoid pollForNotifications(Jdbc42Connection pgConn) throws Exception {\n\t\twhile (!Thread.currentThread().isInterrupted()) {\n\t\t\tfinal PGNotification[] notifications = pgConn.getNotifications();\n\t\t\tif (notifications != null) {\n\t\t\t\tfor (final PGNotification notification : notifications) {\n\t\t\t\t\tSystem.out.println(\n\t\t\t\t\t\t\tnotification.getName() + \": \" +\n\t\t\t\t\t\t\t\t\tnotification.getParameter());\n\t\t\t\t}\n\t\t\t}\n\t\t\tTimeUnit.MILLISECONDS.sleep(100);\n\t\t}\n\t}\n\n\tObservable<PGNotification> observe(String channel, long pollingPeriod) {\n\t\treturn Observable.<PGNotification>create(subscriber -> {\n\t\t\ttry {\n\t\t\t\tConnection connection = DriverManager\n\t\t\t\t\t\t.getConnection(\"jdbc:postgresql:db\");\n\t\t\t\tsubscriber.add(Subscriptions.create(() ->\n\t\t\t\t\t\tcloseQuietly(connection)));\n\t\t\t\tlistenOn(connection, channel);\n\t\t\t\tJdbc42Connection pgConn = (Jdbc42Connection) connection;\n\t\t\t\tpollForNotifications(pollingPeriod, pgConn)\n\t\t\t\t\t\t.subscribe(Subscribers.wrap(subscriber));\n\t\t\t} catch (Exception e) {\n\t\t\t\tsubscriber.onError(e);\n\t\t\t}\n\t\t}).share();\n\t}\n\n\tvoid listenOn(Connection connection, String channel) throws SQLException {\n\t\ttry (Statement statement = connection.createStatement()) {\n\t\t\tstatement.execute(\"LISTEN \" + channel);\n\t\t}\n\t}\n\n\tvoid closeQuietly(Connection connection) {\n\t\ttry {\n\t\t\tconnection.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tObservable<PGNotification> pollForNotifications(\n\t\t\tlong pollingPeriod,\n\t\t\tAbstractJdbc2Connection pgConn) {\n\t\treturn Observable\n\t\t\t\t.interval(0, pollingPeriod, TimeUnit.MILLISECONDS)\n\t\t\t\t.flatMap(x -> tryGetNotification(pgConn))\n\t\t\t\t.filter(arr -> arr != null)\n\t\t\t\t.flatMapIterable(Arrays::asList);\n\t}\n\n\tObservable<PGNotification[]> tryGetNotification(\n\t\t\tAbstractJdbc2Connection pgConn) {\n\t\ttry {\n\t\t\treturn Observable.just(pgConn.getNotifications());\n\t\t} catch (SQLException e) {\n\t\t\treturn Observable.error(e);\n\t\t}\n\t}\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/RestCurrencyServer.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.reactivex.netty.protocol.http.server.HttpServer;\nimport rx.Observable;\n\nimport java.math.BigDecimal;\n\nclass RestCurrencyServer {\n\n    private static final BigDecimal RATE = new BigDecimal(\"1.06448\");\n\n    public static void main(final String[] args) {\n        HttpServer\n                .newServer(8080)\n                .start((req, resp) -> {\n                    String amountStr = req.getDecodedPath().substring(1);\n                    BigDecimal amount = new BigDecimal(amountStr);\n                    Observable<String> response = Observable\n                            .just(amount)\n                            .map(eur -> eur.multiply(RATE))\n                            .map(usd -> \n                                    \"{\\\"EUR\\\": \" + amount + \", \" +\n                                     \"\\\"USD\\\": \" + usd + \"}\");\n                    return resp.writeString(response);\n                })\n                .awaitShutdown();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/RxNettyHttpServer.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport io.reactivex.netty.protocol.http.server.HttpServer;\nimport rx.Observable;\n\nimport static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;\n\nclass RxNettyHttpServer {\n\n    private static final Observable<String> RESPONSE_OK =\n        Observable.just(\"OK\");\n\n    public static void main(String[] args) {\n        HttpServer\n            .newServer(8086)\n            .start((req, resp) ->\n                resp\n                    .setHeader(CONTENT_LENGTH, 2)\n                    .writeStringAndFlushOnEach(RESPONSE_OK)\n            ).awaitShutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/SingleThread.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\nclass SingleThread {\n\n    public static final byte[] RESPONSE = (\n            \"HTTP/1.1 200 OK\\r\\n\" +\n                    \"Content-length: 2\\r\\n\" +\n                    \"\\r\\n\" +\n                    \"OK\").getBytes();\n\n    public static void main(String[] args) throws IOException {\n        final ServerSocket serverSocket = new ServerSocket(8080, 100);\n        while (!Thread.currentThread().isInterrupted()) {\n            final Socket client = serverSocket.accept();\n            handle(client);\n        }\n    }\n\n    private static void handle(Socket client) {\n        try {\n            while (!Thread.currentThread().isInterrupted()) {\n                readFullRequest(client);\n                client.getOutputStream().write(RESPONSE);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            IOUtils.closeQuietly(client);\n        }\n    }\n\n    private static void readFullRequest(Socket client) throws IOException {\n        BufferedReader reader = new BufferedReader(\n                new InputStreamReader(client.getInputStream()));\n        String line = reader.readLine();\n        while (line != null && !line.isEmpty()) {\n            line = reader.readLine();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/Singles.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport com.ning.http.client.AsyncCompletionHandler;\nimport com.ning.http.client.AsyncHttpClient;\nimport com.ning.http.client.Response;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.w3c.dom.Document;\nimport rx.Observable;\nimport rx.Single;\nimport rx.SingleSubscriber;\nimport rx.schedulers.Schedulers;\n\nimport java.io.IOException;\nimport java.time.Instant;\n\n@Ignore\npublic class Singles {\n\n\t@Test\n\tpublic void sample_6() throws Exception {\n\t\tSingle<String> single = Single.just(\"Hello, world!\");\n\t\tsingle.subscribe(System.out::println);\n\n\t\tSingle<Instant> error =\n\t\t\t\tSingle.error(new RuntimeException(\"Opps!\"));\n\t\terror\n\t\t\t\t.observeOn(Schedulers.io())\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tSystem.out::println,\n\t\t\t\t\t\tThrowable::printStackTrace\n\t\t\t\t);\n\t}\n\n\tAsyncHttpClient asyncHttpClient = new AsyncHttpClient();\n\n\tSingle<Response> fetch(String address) {\n\t\treturn Single.create(subscriber ->\n\t\t\t\tasyncHttpClient\n\t\t\t\t\t\t.prepareGet(address)\n\t\t\t\t\t\t.execute(handler(subscriber)));\n\t}\n\n\tAsyncCompletionHandler handler(SingleSubscriber<? super Response> subscriber) {\n\t\treturn new AsyncCompletionHandler() {\n\t\t\tpublic Response onCompleted(Response response) {\n\t\t\t\tsubscriber.onSuccess(response);\n\t\t\t\treturn response;\n\t\t\t}\n\n\t\t\tpublic void onThrowable(Throwable t) {\n\t\t\t\tsubscriber.onError(t);\n\t\t\t}\n\t\t};\n\t}\n\n\t@Test\n\tpublic void sample_55() throws Exception {\n\t\tSingle<String> example =\n\t\t\t\tfetch(\"http://www.example.com\")\n\t\t\t\t\t\t.flatMap(this::body);\n\n\t\tString b = example.toBlocking().value();\n\t}\n\n\tSingle<String> body(Response response) {\n\t\treturn Single.create(subscriber -> {\n\t\t\ttry {\n\t\t\t\tsubscriber.onSuccess(response.getResponseBody());\n\t\t\t} catch (IOException e) {\n\t\t\t\tsubscriber.onError(e);\n\t\t\t}\n\t\t});\n\t}\n\n\t//Same functionality as body():\n\tSingle<String> body2(Response response) {\n\t\treturn Single.fromCallable(() ->\n\t\t\t\tresponse.getResponseBody());\n\t}\n\n\tprivate final JdbcTemplate jdbcTemplate = new JdbcTemplate();\n\n\tSingle<String> content(int id) {\n\t\treturn Single.fromCallable(() -> jdbcTemplate\n\t\t\t\t.queryForObject(\n\t\t\t\t\t\t\"SELECT content FROM articles WHERE id = ?\",\n\t\t\t\t\t\tString.class, id))\n\t\t\t\t.subscribeOn(Schedulers.io());\n\t}\n\n\tSingle<Integer> likes(int id) {\n\t\t//asynchronous HTTP request to social media website\n\t\treturn Single.just(7);\n\t}\n\n\tSingle<Void> updateReadCount() {\n\t\t//only side effect, no return value in Single\n\t\treturn Single.just(null);\n\t}\n\n\t@Test\n\tpublic void sample_98() throws Exception {\n\t\tSingle<Document> doc = Single.zip(\n\t\t\t\tcontent(123),\n\t\t\t\tlikes(123),\n\t\t\t\tupdateReadCount(),\n\t\t\t\t(con, lks, vod) -> buildHtml(con, lks)\n\t\t);\n\t}\n\n\tDocument buildHtml(String content, int likes) {\n\t\t//...\n\t\treturn null;\n\t}\n\n\t@Test\n\tpublic void sample_113() throws Exception {\n\t\tSingle<String> single = Single.create(subscriber -> {\n\t\t\tSystem.out.println(\"Subscribing\");\n\t\t\tsubscriber.onSuccess(\"42\");\n\t\t});\n\n\t\tSingle<String> cachedSingle = single\n\t\t\t\t.toObservable()\n\t\t\t\t.cache()\n\t\t\t\t.toSingle();\n\n\t\tcachedSingle.subscribe(System.out::println);\n\t\tcachedSingle.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_129() throws Exception {\n\t\tSingle<Integer> emptySingle =\n\t\t\t\tObservable.<Integer>empty().toSingle();\n\t\tSingle<Integer> doubleSingle =\n\t\t\t\tObservable.just(1, 2).toSingle();\n\t}\n\n\t@Test\n\tpublic void sample_138() throws Exception {\n\t\tSingle<Integer> ignored = Single\n\t\t\t\t.just(1)\n\t\t\t\t.toObservable()\n\t\t\t\t.ignoreElements()   //PROBLEM\n\t\t\t\t.toSingle();\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/Ticket.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nclass Ticket {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/TravelAgency.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport rx.Observable;\n\nimport java.util.concurrent.CompletableFuture;\n\ninterface TravelAgency {\n\tFlight search(User user, GeoLocation location);\n\n\tdefault CompletableFuture<Flight> searchAsync(User user, GeoLocation location) {\n\t\treturn CompletableFuture.supplyAsync(() -> search(user, location));\n\t}\n\n\tdefault Observable<Flight> rxSearch(User user, GeoLocation location) {\n\t\treturn Observable.fromCallable(() -> search(user, location));\n\t}\n\n}\n\n\nclass SomeTravelAgency implements TravelAgency {\n\n\t@Override\n\tpublic Flight search(User user, GeoLocation location) {\n\t\treturn new Flight();\n\t}\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/User.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport java.time.LocalDate;\n\nclass User {\n\n\tLocalDate getBirth() {\n\t\treturn LocalDate.now().minusYears(30);\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch5/Util.java",
    "content": "package com.oreilly.rxjava.ch5;\n\nimport rx.Observable;\n\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\n\nclass Util {\n    static <T> Observable<T> observe(CompletableFuture<T> future) {\n        return Observable.create(subscriber -> {\n            future.whenComplete((value, exception) -> {\n                if (exception != null) {\n                    subscriber.onError(exception);\n                } else {\n                    subscriber.onNext(value);\n                    subscriber.onCompleted();\n                }\n            });\n        });\n    }\n\n    static <T> CompletableFuture<T> toFuture(Observable<T> observable) {\n        CompletableFuture<T> promise = new CompletableFuture<>();\n        observable\n                .single()\n                .subscribe(\n                        promise::complete,\n                        promise::completeExceptionally\n                );\n        return promise;\n    }\n\n    static <T> CompletableFuture<List<T>> toFutureList(Observable<T> observable) {\n        return toFuture(observable.toList());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/Backpressure.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nimport com.oreilly.rxjava.util.Sleeper;\nimport org.apache.commons.dbutils.ResultSetIterator;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.observables.SyncOnSubscribe;\nimport rx.schedulers.Schedulers;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.time.Duration;\n\n@Ignore\npublic class Backpressure {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Backpressure.class);\n\n\n\tprivate Observable<Dish> dishes() {\n\t\tObservable<Dish> dishes = Observable\n\t\t\t\t.range(1, 1_000_000_000)\n\t\t\t\t.map(Dish::new);\n\t\treturn dishes;\n\t}\n\n\t@Test\n\tpublic void sample_18() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 1_000_000_000)\n\t\t\t\t.map(Dish::new)\n\t\t\t\t.subscribe(x -> {\n\t\t\t\t\tSystem.out.println(\"Washing: \" + x);\n\t\t\t\t\tsleepMillis(50);\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_32() throws Exception {\n\t\tfinal Observable<Dish> dishes = dishes();\n\n\t\tdishes\n\t\t\t\t.observeOn(Schedulers.io())\n\t\t\t\t.subscribe(x -> {\n\t\t\t\t\tSystem.out.println(\"Washing: \" + x);\n\t\t\t\t\tsleepMillis(50);\n\t\t\t\t});\n\n\t}\n\n\tprivate void sleepMillis(int millis) {\n\t\tSleeper.sleep(Duration.ofMillis(millis));\n\t}\n\n\tObservable<Integer> myRange(int from, int count) {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tint i = from;\n\t\t\twhile (i < from + count) {\n\t\t\t\tif (!subscriber.isUnsubscribed()) {\n\t\t\t\t\tsubscriber.onNext(i++);\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsubscriber.onCompleted();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_65() throws Exception {\n\t\tmyRange(1, 1_000_000_000)\n\t\t\t\t.map(Dish::new)\n\t\t\t\t.observeOn(Schedulers.io())\n\t\t\t\t.subscribe(x -> {\n\t\t\t\t\t\t\tSystem.out.println(\"Washing: \" + x);\n\t\t\t\t\t\t\tsleepMillis(50);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tThrowable::printStackTrace\n\t\t\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_78() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 10)\n\t\t\t\t.subscribe(new Subscriber<Integer>() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onStart() {\n\t\t\t\t\t\trequest(3);\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onCompleted() {\n\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onError(Throwable e) {\n\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onNext(Integer integer) {\n\n\t\t\t\t\t}\n\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_94() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 10)\n\t\t\t\t.subscribe(new Subscriber<Integer>() {\n\n\t\t\t\t\t{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trequest(3);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onCompleted() {\n\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onError(Throwable e) {\n\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onNext(Integer integer) {\n\n\t\t\t\t\t}\n\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_136() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 10)\n\t\t\t\t.subscribe(new Subscriber<Integer>() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onStart() {\n\t\t\t\t\t\trequest(1);\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onCompleted() {\n\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onError(Throwable e) {\n\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onNext(Integer integer) {\n\t\t\t\t\t\trequest(1);\n\t\t\t\t\t\tlog.info(\"Next {}\", integer);\n\t\t\t\t\t}\n\n\t\t\t\t\t//onCompleted, onError...\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_173() throws Exception {\n\t\tmyRange(1, 1_000_000_000)\n\t\t\t\t.map(Dish::new)\n\t\t\t\t.onBackpressureBuffer()\n\t\t\t\t//.onBackpressureBuffer(1000, () -> log.warn(\"Buffer full\"))\n\t\t\t\t//.onBackpressureDrop(dish -> log.warn(\"Throw away {}\", dish))\n\t\t\t\t.observeOn(Schedulers.io())\n\t\t\t\t.subscribe(x -> {\n\t\t\t\t\tSystem.out.println(\"Washing: \" + x);\n\t\t\t\t\tsleepMillis(50);\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_189() throws Exception {\n\t\tConnection connection = null;\n\t\tPreparedStatement statement =\n\t\t\t\tconnection.prepareStatement(\"SELECT ...\");\n\t\tstatement.setFetchSize(1000);\n\t\tResultSet rs = statement.executeQuery();\n\t\tObservable<Object[]> result =\n\t\t\t\tObservable\n\t\t\t\t\t\t.from(ResultSetIterator.iterable(rs))\n\t\t\t\t\t\t.doAfterTerminate(() -> {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\trs.close();\n\t\t\t\t\t\t\t\tstatement.close();\n\t\t\t\t\t\t\t\tconnection.close();\n\t\t\t\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\t\t\t\tlog.warn(\"Unable to close\", e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_213() throws Exception {\n\t\tObservable.OnSubscribe<Double> onSubscribe =\n\t\t\t\tSyncOnSubscribe.createStateless(\n\t\t\t\t\t\tobserver -> observer.onNext(Math.random())\n\t\t\t\t);\n\n\t\tObservable<Double> rand = Observable.create(onSubscribe);\n\t}\n\n\t@Test\n\tpublic void sample_224() throws Exception {\n\t\tObservable.OnSubscribe<Long> onSubscribe =\n\t\t\t\tSyncOnSubscribe.createStateful(\n\t\t\t\t\t\t() -> 0L,\n\t\t\t\t\t\t(cur, observer) -> {\n\t\t\t\t\t\t\tobserver.onNext(cur);\n\t\t\t\t\t\t\treturn cur + 1;\n\t\t\t\t\t\t}\n\t\t\t\t);\n\n\t\tObservable<Long> naturals = Observable.create(onSubscribe);\n\t}\n\n\t@Test\n\tpublic void sample_238() throws Exception {\n\t\tObservable<Long> naturals = Observable.create(subscriber -> {\n\t\t\tlong cur = 0;\n\t\t\twhile (!subscriber.isUnsubscribed()) {\n\t\t\t\tSystem.out.println(\"Produced: \" + cur);\n\t\t\t\tsubscriber.onNext(cur++);\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_249() throws Exception {\n\t\tResultSet resultSet = null; //...\n\n\t\tObservable.OnSubscribe<Object[]> onSubscribe = SyncOnSubscribe.createSingleState(\n\t\t\t\t() -> resultSet,\n\t\t\t\t(rs, observer) -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\trs.next();\n\t\t\t\t\t\tobserver.onNext(toArray(rs));\n\t\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\t\tobserver.onError(e);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\trs -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t//Also close Statement, Connection, etc.\n\t\t\t\t\t\trs.close();\n\t\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\t\tlog.warn(\"Unable to close\", e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t);\n\n\t\tObservable<Object[]> records = Observable.create(onSubscribe);\n\n\t}\n\n\tprivate Object[] toArray(ResultSet rs) {\n\t\t//TODO\n\t\treturn new Object[] {};\n\t}\n\n\t@Test\n\tpublic void sample_284() throws Exception {\n\t\tObservable<Integer> source = Observable.range(1, 1_000);\n\n\t\tsource.subscribe(this::store);\n\n\t\tsource\n\t\t\t\t.flatMap(this::store)\n\t\t\t\t.subscribe(uuid -> log.debug(\"Stored: {}\", uuid));\n\n\t\tsource\n\t\t\t\t.flatMap(this::store)\n\t\t\t\t.buffer(100)\n\t\t\t\t.subscribe(\n\t\t\t\t\t\thundredUuids -> log.debug(\"Stored: {}\", hundredUuids));\n\t}\n\n\tObservable<Void> store(int x) {\n\t\treturn Observable.empty();\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/Chapter6.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\n\nimport java.time.Duration;\nimport java.time.LocalTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.stream.Collectors;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static rx.Observable.empty;\nimport static rx.Observable.just;\n\n@Ignore\npublic class Chapter6 {\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tlong startTime = System.currentTimeMillis();\n\t\tObservable\n\t\t\t\t.interval(7, MILLISECONDS)\n\t\t\t\t.timestamp()\n\t\t\t\t.sample(1, SECONDS)\n\t\t\t\t.map(ts -> ts.getTimestampMillis() - startTime + \"ms: \" + ts.getValue())\n\t\t\t\t.take(5)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_25() throws Exception {\n\t\tObservable<String> delayedNames = delayedNames();\n\n\t\tdelayedNames\n\t\t\t\t.sample(1, SECONDS)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_37() throws Exception {\n\t\tObservable<String> delayedNames = delayedNames();\n\n\t\tdelayedNames\n\t\t\t\t.concatWith(delayedCompletion())\n\t\t\t\t.sample(1, SECONDS)\n\t\t\t\t.subscribe(System.out::println);\n\n\t}\n\n\tprivate Observable<String> delayedNames() {\n\t\tObservable<String> names =\n\t\t\t\tjust(\"Mary\", \"Patricia\", \"Linda\",\n\t\t\t\t\t\t\"Barbara\",\n\t\t\t\t\t\t\"Elizabeth\", \"Jennifer\", \"Maria\", \"Susan\",\n\t\t\t\t\t\t\"Margaret\", \"Dorothy\");\n\n\t\tObservable<Long> absoluteDelayMillis =\n\t\t\t\tjust(0.1, 0.6, 0.9,\n\t\t\t\t\t\t1.1,\n\t\t\t\t\t\t3.3, 3.4, 3.5, 3.6,\n\t\t\t\t\t\t4.4, 4.8)\n\t\t\t\t\t\t.map(d -> (long) (d * 1_000));\n\n\t\tfinal Observable<String> delayedNames = names\n\t\t\t\t.zipWith(absoluteDelayMillis,\n\t\t\t\t\t\t(n, d) ->\n\t\t\t\t\t\t\t\tjust(n)\n\t\t\t\t\t\t\t\t\t\t.delay(d, MILLISECONDS))\n\t\t\t\t.flatMap(o -> o);\n\t\treturn delayedNames;\n\t}\n\n\tstatic <T> Observable<T> delayedCompletion() {\n\t\treturn Observable.<T>empty().delay(1, SECONDS);\n\t}\n\n\t@Test\n\tpublic void sample_64() throws Exception {\n\t\tObservable<Long> obs = Observable.interval(20, MILLISECONDS);\n\n\t\t//equivalent:\n\t\tobs.sample(1, SECONDS);\n\t\tobs.sample(Observable.interval(1, SECONDS));\n\t}\n\n\t@Test\n\tpublic void sample_73() throws Exception {\n\t\tObservable<String> delayedNames = delayedNames();\n\n\t\tdelayedNames\n\t\t\t\t.throttleFirst(1, SECONDS)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_93() throws Exception {\n\t\tObservable\n\t\t\t\t.range(1, 7)  //1, 2, 3, ... 7\n\t\t\t\t.buffer(3)\n\t\t\t\t.subscribe((List<Integer> list) -> {\n\t\t\t\t\t\t\tSystem.out.println(list);\n\t\t\t\t\t\t}\n\t\t\t\t);\n\t}\n\n\tRepository repository = new SomeRepository();\n\n\t@Test\n\tpublic void sample_105() throws Exception {\n\t\tObservable<Record> events = Observable.range(1, 100).map(x -> new Record());\n\n\t\tevents\n\t\t\t\t.subscribe(repository::store);\n//vs.\n\t\tevents\n\t\t\t\t.buffer(10)\n\t\t\t\t.subscribe(repository::storeAll);\n\n\t}\n\n\t@Test\n\tpublic void sample_120() throws Exception {\n\t\tRandom random = new Random();\n\t\tObservable\n\t\t\t\t.defer(() -> just(random.nextGaussian()))\n\t\t\t\t.repeat(1000)\n\t\t\t\t.buffer(100, 1)\n\t\t\t\t.map(this::averageOfList)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\tprivate double averageOfList(List<Double> list) {\n\t\treturn list\n\t\t\t\t.stream()\n\t\t\t\t.collect(Collectors.averagingDouble(x -> x));\n\t}\n\n\t@Test\n\tpublic void sample_139() throws Exception {\n\t\tObservable<List<Integer>> odd = Observable\n\t\t\t\t.range(1, 7)\n\t\t\t\t.buffer(1, 2);\n\t\todd.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_147() throws Exception {\n\t\tObservable<Integer> odd = Observable\n\t\t\t\t.range(1, 7)\n\t\t\t\t.buffer(1, 2)\n\t\t\t\t.flatMapIterable(list -> list);\n\t}\n\n\t@Test\n\tpublic void sample_155() throws Exception {\n\t\tObservable<String> delayedNames = delayedNames();\n\n\t\tdelayedNames\n\t\t\t\t.buffer(1, SECONDS)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_164() throws Exception {\n\t\tObservable<KeyEvent> keyEvents = empty();\n\n\t\tObservable<Integer> eventPerSecond = keyEvents\n\t\t\t\t.buffer(1, SECONDS)\n\t\t\t\t.map(List::size);\n\t}\n\n\t@Test\n\tpublic void sample_173() throws Exception {\n\t\tObservable<Duration> insideBusinessHours = Observable\n\t\t\t\t.interval(1, SECONDS)\n\t\t\t\t.filter(x -> isBusinessHour())\n\t\t\t\t.map(x -> Duration.ofMillis(100));\n\t\tObservable<Duration> outsideBusinessHours = Observable\n\t\t\t\t.interval(5, SECONDS)\n\t\t\t\t.filter(x -> !isBusinessHour())\n\t\t\t\t.map(x -> Duration.ofMillis(200));\n\n\t\tObservable<Duration> openings = Observable.merge(\n\t\t\t\tinsideBusinessHours, outsideBusinessHours);\n\n\t\tObservable<TeleData> upstream = empty();\n\n\t\tObservable<List<TeleData>> samples = upstream\n\t\t\t\t.buffer(openings);\n\n\t\tObservable<List<TeleData>> samples2 = upstream\n\t\t\t\t.buffer(\n\t\t\t\t\t\topenings,\n\t\t\t\t\t\tduration -> empty()\n\t\t\t\t\t\t\t\t.delay(duration.toMillis(), MILLISECONDS));\n\n\t}\n\n\tprivate static final LocalTime BUSINESS_START = LocalTime.of(9, 0);\n\tprivate static final LocalTime BUSINESS_END = LocalTime.of(17, 0);\n\n\tprivate boolean isBusinessHour() {\n\t\tZoneId zone = ZoneId.of(\"Europe/Warsaw\");\n\t\tZonedDateTime zdt = ZonedDateTime.now(zone);\n\t\tLocalTime localTime = zdt.toLocalTime();\n\t\treturn !localTime.isBefore(BUSINESS_START)\n\t\t\t\t&& !localTime.isAfter(BUSINESS_END);\n\t}\n\n\t@Test\n\tpublic void sample_216() throws Exception {\n\t\tObservable<KeyEvent> keyEvents = empty();\n\n\t\tObservable<Observable<KeyEvent>> windows = keyEvents.window(1, SECONDS);\n\t\tObservable<Integer> eventPerSecond = windows\n\t\t\t\t.flatMap(eventsInSecond -> eventsInSecond.count());\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/Debounce.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.observables.ConnectableObservable;\n\nimport java.math.BigDecimal;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static rx.Observable.defer;\n\n@Ignore\npublic class Debounce {\n\n\n\tprivate final TradingPlatform tradingPlatform = new TradingPlatform();\n\n\t@Test\n\tpublic void sample_225() throws Exception {\n\t\tObservable<BigDecimal> prices = tradingPlatform.pricesOf(\"NFLX\");\n\t\tObservable<BigDecimal> debounced = prices.debounce(100, MILLISECONDS);\n\n\t\tprices\n\t\t\t\t.debounce(x -> {\n\t\t\t\t\tboolean goodPrice = x.compareTo(BigDecimal.valueOf(150)) > 0;\n\t\t\t\t\treturn Observable\n\t\t\t\t\t\t\t.empty()\n\t\t\t\t\t\t\t.delay(goodPrice? 10 : 100, MILLISECONDS);\n\t\t\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_242() throws Exception {\n\t\tObservable\n\t\t\t\t.interval(99, MILLISECONDS)\n\t\t\t\t.debounce(100, MILLISECONDS);\n\t}\n\n\t@Test\n\tpublic void sample_249() throws Exception {\n\t\tObservable\n\t\t\t\t.interval(99, MILLISECONDS)\n\t\t\t\t.debounce(100, MILLISECONDS)\n\t\t\t\t.timeout(1, SECONDS);\n\t}\n\n\t@Test\n\tpublic void sample_48() throws Exception {\n\t\tConnectableObservable<Long> upstream = Observable\n\t\t\t\t.interval(99, MILLISECONDS)\n\t\t\t\t.publish();\n\t\tupstream\n\t\t\t\t.debounce(100, MILLISECONDS)\n\t\t\t\t.timeout(1, SECONDS, upstream.take(1));\n\t\tupstream.connect();\n\t}\n\n\t@Test\n\tpublic void sample_60() throws Exception {\n\t\tfinal Observable<Long> upstream = Observable.interval(99, MILLISECONDS);\n\n\t\tupstream\n\t\t\t\t.debounce(100, MILLISECONDS)\n\t\t\t\t.timeout(1, SECONDS, upstream\n\t\t\t\t\t\t.take(1)\n\t\t\t\t\t\t.concatWith(\n\t\t\t\t\t\t\t\tupstream.debounce(100, MILLISECONDS)));\n\t}\n\n\t@Test\n\tpublic void sample_72() throws Exception {\n\t\tfinal Observable<Long> upstream = Observable.interval(99, MILLISECONDS);\n\n\t\tupstream\n\t\t\t\t.debounce(100, MILLISECONDS)\n\t\t\t\t.timeout(1, SECONDS, upstream\n\t\t\t\t\t\t.take(1)\n\t\t\t\t\t\t.concatWith(\n\t\t\t\t\t\t\t\tupstream\n\t\t\t\t\t\t\t\t\t\t.debounce(100, MILLISECONDS)\n\t\t\t\t\t\t\t\t\t\t.timeout(1, SECONDS, upstream)));\n\t}\n\n\tObservable<Long> timedDebounce(Observable<Long> upstream) {\n\t\tObservable<Long> onTimeout = upstream\n\t\t\t\t.take(1)\n\t\t\t\t.concatWith(defer(() -> timedDebounce(upstream)));\n\t\treturn upstream\n\t\t\t\t.debounce(100, MILLISECONDS)\n\t\t\t\t.timeout(1, SECONDS, onTimeout);\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/Dish.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nclass Dish {\n    private final byte[] oneKb = new byte[1_024];\n    private final int id;\n\n    Dish(int id) {\n        this.id = id;\n        System.out.println(\"Created: \" + id);\n    }\n\n    public String toString() {\n        return String.valueOf(id);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/KeyEvent.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nclass KeyEvent {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/Record.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nclass Record {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/Repository.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nimport java.util.List;\n\ninterface Repository {\n    void store(Record record);\n    void storeAll(List<Record> records);\n}\n\nclass SomeRepository implements Repository {\n    @Override\n    public void store(Record record) {\n    }\n\n    @Override\n    public void storeAll(List<Record> records) {\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/TeleData.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nclass TeleData {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch6/TradingPlatform.java",
    "content": "package com.oreilly.rxjava.ch6;\n\nimport rx.Observable;\n\nimport java.math.BigDecimal;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\n\nclass TradingPlatform {\n\n\tObservable<BigDecimal> pricesOf(String ticker) {\n\t\treturn Observable\n\t\t\t\t.interval(50, MILLISECONDS)\n\t\t\t\t.flatMap(this::randomDelay)\n\t\t\t\t.map(this::randomStockPrice)\n\t\t\t\t.map(BigDecimal::valueOf);\n\t}\n\n\tObservable<Long> randomDelay(long x) {\n\t\treturn Observable\n\t\t\t\t.just(x)\n\t\t\t\t.delay((long) (Math.random() * 100), MILLISECONDS);\n\t}\n\n\tdouble randomStockPrice(long x) {\n\t\treturn 100 + Math.random() * 10 +\n\t\t\t\t(Math.sin(x / 100.0)) * 60.0;\n\t}\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/Agreement.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nclass Agreement {\n\tboolean postalMailRequired() {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/Chapter7.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.schedulers.TimeInterval;\n\nimport java.math.BigInteger;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport static java.time.Month.*;\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\n\n@Ignore\npublic class Chapter7 {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Chapter7.class);\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tObservable\n\t\t\t\t.create(subscriber -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsubscriber.onNext(1 / 0);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tsubscriber.onError(e);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t//BROKEN, missing onError() callback\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_29() throws Exception {\n\t\tObservable\n\t\t\t\t.create(subscriber -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsubscriber.onNext(1 / 0);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tsubscriber.onError(e);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tSystem.out::println,\n\t\t\t\t\t\tthrowable -> log.error(\"That escalated quickly\", throwable));\n\n\t}\n\n\t@Test\n\tpublic void sample_45() throws Exception {\n\t\tObservable.create(subscriber -> {\n\t\t\ttry {\n\t\t\t\tsubscriber.onNext(1 / 0);\n\t\t\t} catch (Exception e) {\n\t\t\t\tsubscriber.onError(e);\n\t\t\t}\n\t\t});\n\n\t\tObservable.create(subscriber -> subscriber.onNext(1 / 0));\n\n\t\tObservable.fromCallable(() -> 1 / 0);\n\t}\n\n\t@Test\n\tpublic void sample_60() throws Exception {\n\t\tObservable\n\t\t\t\t.just(1, 0)\n\t\t\t\t.map(x -> 10 / x);\n\n\t\tObservable\n\t\t\t\t.just(\"Lorem\", null, \"ipsum\")\n\t\t\t\t.filter(String::isEmpty);\n\t}\n\n\t@Test\n\tpublic void sample_71() throws Exception {\n\t\tObservable\n\t\t\t\t.just(1, 0)\n\t\t\t\t.flatMap(x -> (x == 0) ?\n\t\t\t\t\t\tObservable.error(new ArithmeticException(\"Zero :-(\")) :\n\t\t\t\t\t\tObservable.just(10 / x)\n\t\t\t\t);\n\t}\n\n\n\tprivate final PrintHouse printHouse = new PrintHouse();\n\n\t@Test\n\tpublic void sample_81() throws Exception {\n\t\tObservable<Person> person = Observable.just(new Person());\n\t\tObservable<InsuranceContract> insurance = Observable.just(new InsuranceContract());\n\t\tObservable<Health> health = person.flatMap(this::checkHealth);\n\t\tObservable<Income> income = person.flatMap(this::determineIncome);\n\t\tObservable<Score> score = Observable\n\t\t\t\t.zip(health, income, (h, i) -> asses(h, i))\n\t\t\t\t.map(this::translate);\n\t\tObservable<Agreement> agreement = Observable.zip(\n\t\t\t\tinsurance,\n\t\t\t\tscore.filter(Score::isHigh),\n\t\t\t\tthis::prepare);\n\t\tObservable<TrackingId> mail = agreement\n\t\t\t\t.filter(Agreement::postalMailRequired)\n\t\t\t\t.flatMap(this::print)\n\t\t\t\t.flatMap(printHouse::deliver);\n\t}\n\n\tprivate Observable<Agreement> print(Agreement agreement) {\n\t\treturn Observable.just(agreement);\n\t}\n\n\tprivate Agreement prepare(InsuranceContract contract, Score score) {\n\t\treturn new Agreement();\n\t}\n\n\tprivate Score translate(BigInteger score) {\n\t\treturn new Score();\n\t}\n\n\tprivate BigInteger asses(Health h, Income i) {\n\t\treturn BigInteger.ONE;\n\t}\n\n\tprivate Observable<Income> determineIncome(Person person) {\n\t\treturn Observable.error(new RuntimeException(\"Foo\"));\n\t}\n\n\tprivate Observable<Health> checkHealth(Person person) {\n\t\treturn Observable.just(new Health());\n\t}\n\n\t@Test\n\tpublic void sample_129() throws Exception {\n\t\tObservable<Person> person = Observable.just(new Person());\n\t\tObservable<Income> income = person\n\t\t\t\t.flatMap(this::determineIncome)\n\t\t\t\t.onErrorReturn(error -> Income.no());\n\t}\n\n\tpublic Observable<Income> sample_137() throws Exception {\n\t\tPerson person = new Person();\n\t\ttry {\n\t\t\treturn determineIncome(person);\n\t\t} catch (Exception e) {\n\t\t\treturn Observable.just(Income.no());\n\t\t}\n\t}\n\n\t@Test\n\tpublic void sample_147() throws Exception {\n\t\tObservable<Person> person = Observable.just(new Person());\n\t\tObservable<Income> income = person\n\t\t\t\t.flatMap(this::determineIncome)\n\t\t\t\t.onErrorResumeNext(person.flatMap(this::guessIncome));\n\n\t}\n\n\tprivate Observable<Income> guessIncome(Person person) {\n\t\t//...\n\t\treturn Observable.just(new Income(1));\n\t}\n\n\t@Test\n\tpublic void sample_161() throws Exception {\n\t\tObservable<Person> person = Observable.just(new Person());\n\n\t\tObservable<Income> income = person\n\t\t\t\t.flatMap(this::determineIncome)\n\t\t\t\t.flatMap(\n\t\t\t\t\t\tObservable::just,\n\t\t\t\t\t\tth -> Observable.empty(),\n\t\t\t\t\t\tObservable::empty)\n\t\t\t\t.concatWith(person.flatMap(this::guessIncome))\n\t\t\t\t.first();\n\t}\n\n\t@Test\n\tpublic void sample_175() throws Exception {\n\t\tObservable<Person> person = Observable.just(new Person());\n\n\t\tObservable<Income> income = person\n\t\t\t\t.flatMap(this::determineIncome)\n\t\t\t\t.flatMap(\n\t\t\t\t\t\tObservable::just,\n\t\t\t\t\t\tth -> person.flatMap(this::guessIncome),\n\t\t\t\t\t\tObservable::empty);\n\t}\n\n\t@Test\n\tpublic void sample_187() throws Exception {\n\t\tObservable<Person> person = Observable.just(new Person());\n\n\t\tObservable<Income> income = person\n\t\t\t\t.flatMap(this::determineIncome)\n\t\t\t\t.onErrorResumeNext(th -> {\n\t\t\t\t\tif (th instanceof NullPointerException) {\n\t\t\t\t\t\treturn Observable.error(th);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn person.flatMap(this::guessIncome);\n\t\t\t\t\t}\n\t\t\t\t});\n\t}\n\n\tObservable<Confirmation> confirmation() {\n\t\tObservable<Confirmation> delayBeforeCompletion =\n\t\t\t\tObservable\n\t\t\t\t\t\t.<Confirmation>empty()\n\t\t\t\t\t\t.delay(200, MILLISECONDS);\n\t\treturn Observable\n\t\t\t\t.just(new Confirmation())\n\t\t\t\t.delay(100, MILLISECONDS)\n\t\t\t\t.concatWith(delayBeforeCompletion);\n\t}\n\n\t@Test\n\tpublic void sample_215() throws Exception {\n\t\tconfirmation()\n\t\t\t\t.timeout(210, MILLISECONDS)\n\t\t\t\t.forEach(\n\t\t\t\t\t\tSystem.out::println,\n\t\t\t\t\t\tth -> {\n\t\t\t\t\t\t\tif ((th instanceof TimeoutException)) {\n\t\t\t\t\t\t\t\tSystem.out.println(\"Too long\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tth.printStackTrace();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t);\n\t}\n\n\tObservable<LocalDate> nextSolarEclipse(LocalDate after) {\n\t\treturn Observable\n\t\t\t\t.just(\n\t\t\t\t\t\tLocalDate.of(2016, MARCH, 9),\n\t\t\t\t\t\tLocalDate.of(2016, SEPTEMBER, 1),\n\t\t\t\t\t\tLocalDate.of(2017, FEBRUARY, 26),\n\t\t\t\t\t\tLocalDate.of(2017, AUGUST, 21),\n\t\t\t\t\t\tLocalDate.of(2018, FEBRUARY, 15),\n\t\t\t\t\t\tLocalDate.of(2018, JULY, 13),\n\t\t\t\t\t\tLocalDate.of(2018, AUGUST, 11),\n\t\t\t\t\t\tLocalDate.of(2019, JANUARY, 6),\n\t\t\t\t\t\tLocalDate.of(2019, JULY, 2),\n\t\t\t\t\t\tLocalDate.of(2019, DECEMBER, 26))\n\t\t\t\t.skipWhile(date -> !date.isAfter(after))\n\t\t\t\t.zipWith(\n\t\t\t\t\t\tObservable.interval(500, 50, MILLISECONDS),\n\t\t\t\t\t\t(date, x) -> date);\n\t}\n\n\t@Test\n\tpublic void sample_253() throws Exception {\n\t\tnextSolarEclipse(LocalDate.of(2016, SEPTEMBER, 1))\n\t\t\t\t.timeout(\n\t\t\t\t\t\t() -> Observable.timer(1000, TimeUnit.MILLISECONDS),\n\t\t\t\t\t\tdate -> Observable.timer(100, MILLISECONDS));\n\t}\n\n\t@Test\n\tpublic void sample_262() throws Exception {\n\t\tObservable<TimeInterval<LocalDate>> intervals =\n\t\t\t\tnextSolarEclipse(LocalDate.of(2016, JANUARY, 1))\n\t\t\t\t\t\t.timeInterval();\n\t}\n\n\t@Test\n\tpublic void sample_271() throws Exception {\n\t\tObservable<Instant> timestamps = Observable\n\t\t\t\t.fromCallable(() -> dbQuery())\n\t\t\t\t.doOnSubscribe(() -> log.info(\"subscribe()\"))\n\t\t\t\t.doOnRequest(c -> log.info(\"Requested {}\", c))\n\t\t\t\t.doOnNext(instant -> log.info(\"Got: {}\", instant));\n\n\t\ttimestamps\n\t\t\t\t.zipWith(timestamps.skip(1), Duration::between)\n\t\t\t\t.map(Object::toString)\n\t\t\t\t.subscribe(log::info);\n\t}\n\n\tprivate Instant dbQuery() {\n\t\treturn Instant.now();\n\t}\n\n\t@Test\n\tpublic void sample_291() throws Exception {\n\t\tObservable<String> obs = Observable\n\t\t\t\t.<String>error(new RuntimeException(\"Swallowed\"))\n\t\t\t\t.doOnError(th -> log.warn(\"onError\", th))\n\t\t\t\t.onErrorReturn(th -> \"Fallback\");\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/Confirmation.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nclass Confirmation {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/Monitoring.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport com.codahale.metrics.Counter;\nimport com.codahale.metrics.MetricRegistry;\nimport com.codahale.metrics.Slf4jReporter;\nimport com.codahale.metrics.Timer;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\n\nimport java.util.concurrent.TimeUnit;\n\n@Ignore\npublic class Monitoring {\n\n\tprivate MetricRegistry metricRegistry;\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tmetricRegistry = new MetricRegistry();\n\t\tSlf4jReporter reporter = Slf4jReporter\n\t\t\t\t.forRegistry(metricRegistry)\n\t\t\t\t.outputTo(LoggerFactory.getLogger(Monitoring.class))\n\t\t\t\t.build();\n\t\treporter.start(1, TimeUnit.SECONDS);\n\t}\n\n\t@Test\n\tpublic void sample_26() throws Exception {\n\t\tfinal Observable<Integer> observable = Observable.range(1, 100);\n\t\tfinal Counter items = metricRegistry.counter(\"items\");\n\t\tobservable\n\t\t\t\t.doOnNext(x -> items.inc())\n\t\t\t\t.subscribe(/* ... */);\n\t}\n\n\tObservable<Long> makeNetworkCall(long x) {\n\t\t//...\n\t\treturn Observable.just(10L);\n\t}\n\n\t@Test\n\tpublic void sample_38() throws Exception {\n\t\tfinal Observable<Integer> observable = Observable.range(1, 100);\n\n\t\tCounter counter = metricRegistry.counter(\"counter\");\n\t\tobservable\n\t\t\t\t.doOnNext(x -> counter.inc())\n\t\t\t\t.flatMap(this::makeNetworkCall)\n\t\t\t\t.doOnNext(x -> counter.dec())\n\t\t\t\t.subscribe(/* ... */);\n\t}\n\n\t@Test\n\tpublic void sample_55() throws Exception {\n\t\tfinal Observable<Integer> observable = Observable.range(1, 100);\n\t\tCounter counter = metricRegistry.counter(\"counter\");\n\n\t\tobservable\n\t\t\t\t.flatMap(x ->\n\t\t\t\t\t\tmakeNetworkCall(x)\n\t\t\t\t\t\t\t\t.doOnSubscribe(counter::inc)\n\t\t\t\t\t\t\t\t.doOnTerminate(counter::dec)\n\t\t\t\t)\n\t\t\t\t.subscribe(/* ... */);\n\t}\n\n\t@Test\n\tpublic void sample_69() throws Exception {\n\t\tTimer timer = metricRegistry.timer(\"timer\");\n\t\tTimer.Context ctx = timer.time();\n\t\t//some lengthy operation...\n\t\tctx.stop();\n\t}\n\n\t@Test\n\tpublic void sample_78() throws Exception {\n\t\tObservable<Long> external = Observable.just(42L);\n\n\t\tTimer timer = metricRegistry.timer(\"timer\");\n\n\t\tObservable<Long> externalWithTimer = Observable\n\t\t\t\t.defer(() -> Observable.just(timer.time()))\n\t\t\t\t.flatMap(timerCtx ->\n\t\t\t\t\t\texternal.doOnCompleted(timerCtx::stop));\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/MyService.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport rx.Observable;\n\nimport java.time.LocalDate;\n\ninterface MyService {\n    Observable<LocalDate> externalCall();\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/MyServiceWithTimeout.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport rx.Observable;\nimport rx.Scheduler;\n\nimport java.time.LocalDate;\nimport java.util.concurrent.TimeUnit;\n\nclass MyServiceWithTimeout implements MyService {\n\n    private final MyService delegate;\n    private final Scheduler scheduler;\n\n    MyServiceWithTimeout(MyService d, Scheduler s) {\n        this.delegate = d;\n        this.scheduler = s;\n    }\n\n    @Override\n    public Observable<LocalDate> externalCall() {\n        return delegate\n                .externalCall()\n                .timeout(1, TimeUnit.SECONDS,\n                     Observable.empty(),\n                     scheduler);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/Person.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nclass Person {\n}\n\nclass Health {\n}\n\nclass Score {\n\tboolean isHigh() {\n\t\treturn true;\n\t}\n}\n\nclass InsuranceContract {\n}\n\nclass Income {\n\n\n\tpublic Income(int i) {\n\t}\n\n\tstatic Income no() {\n\t\treturn new Income(0);\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/PrintHouse.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport rx.Observable;\n\nclass PrintHouse {\n\n\tObservable<TrackingId> deliver(Agreement agreement) {\n\t\treturn Observable.just(new TrackingId());\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/RetryTimeouts.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\n\nimport java.util.concurrent.TimeoutException;\n\nimport static java.util.concurrent.TimeUnit.SECONDS;\n\n@Ignore\npublic class RetryTimeouts {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(RetryTimeouts.class);\n\n\tObservable<String> risky() {\n\t\treturn Observable.fromCallable(() -> {\n\t\t\tif (Math.random() < 0.1) {\n\t\t\t\tThread.sleep((long) (Math.random() * 2000));\n\t\t\t\treturn \"OK\";\n\t\t\t} else {\n\t\t\t\tthrow new RuntimeException(\"Transient\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tpublic void sample_281() throws Exception {\n\t\trisky()\n\t\t\t\t.timeout(1, SECONDS)\n\t\t\t\t.doOnError(th -> log.warn(\"Will retry\", th))\n\t\t\t\t.retry()\n\t\t\t\t.subscribe(log::info);\n\t}\n\n\t@Test\n\tpublic void sample_291() throws Exception {\n\t\trisky().cache().retry();  //BROKEN\n\t}\n\n\t@Test\n\tpublic void sample_296() throws Exception {\n\t\tObservable\n\t\t\t\t.defer(() -> risky())\n\t\t\t\t.retry();\n\t}\n\n\t@Test\n\tpublic void sample_303() throws Exception {\n\t\trisky()\n\t\t\t\t.timeout(1, SECONDS)\n\t\t\t\t.retry(10);\n\t}\n\n\t@Test\n\tpublic void sample_310() throws Exception {\n\t\trisky()\n\t\t\t\t.timeout(1, SECONDS)\n\t\t\t\t.retry((attempt, e) ->\n\t\t\t\t\t\tattempt <= 10 && !(e instanceof TimeoutException));\n\t}\n\n\t@Test\n\tpublic void sample_66() throws Exception {\n\t\trisky()\n\t\t\t\t.timeout(1, SECONDS)\n//\t\t\t\t.retryWhen(failures -> failures.take(10))\n\t\t\t\t.retryWhen(failures -> failures.delay(1, SECONDS));\n\t}\n\n\tprivate static final int ATTEMPTS = 11;\n\n\t@Test\n\tpublic void sample_74() throws Exception {\n\t\trisky()\n\t\t\t\t.timeout(1, SECONDS)\n\t\t\t\t.retryWhen(failures -> failures\n\t\t\t\t\t\t.zipWith(Observable.range(1, ATTEMPTS), (err, attempt) ->\n\t\t\t\t\t\t\t\tattempt < ATTEMPTS ?\n\t\t\t\t\t\t\t\t\t\tObservable.timer(1, SECONDS) :\n\t\t\t\t\t\t\t\t\t\tObservable.error(err))\n\t\t\t\t\t\t.flatMap(x -> x)\n\t\t\t\t);\n\t}\n\n\t@Test\n\tpublic void sample_89() throws Exception {\n\t\trisky()\n\t\t\t\t.timeout(1, SECONDS)\n\t\t\t\t.retryWhen(failures -> failures\n\t\t\t\t\t\t.zipWith(Observable.range(1, ATTEMPTS),\n\t\t\t\t\t\t\t\tthis::handleRetryAttempt)\n\t\t\t\t\t\t.flatMap(x -> x)\n\t\t\t\t);\n\t}\n\n\tObservable<Long> handleRetryAttempt(Throwable err, int attempt) {\n\t\tswitch (attempt) {\n\t\t\tcase 1:\n\t\t\t\treturn Observable.just(42L);\n\t\t\tcase ATTEMPTS:\n\t\t\t\treturn Observable.error(err);\n\t\t\tdefault:\n\t\t\t\tlong expDelay = (long) Math.pow(2, attempt - 2);\n\t\t\t\treturn Observable.timer(expDelay, SECONDS);\n\t\t}\n\t}\n\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/Testing.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nimport com.google.common.io.Files;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Notification;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.observables.BlockingObservable;\nimport rx.observables.SyncOnSubscribe;\nimport rx.observers.TestSubscriber;\nimport rx.plugins.RxJavaPlugins;\nimport rx.plugins.RxJavaSchedulersHook;\nimport rx.schedulers.Schedulers;\nimport rx.schedulers.TestScheduler;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.time.LocalDate;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static org.assertj.core.api.AssertionsForClassTypes.failBecauseExceptionWasNotThrown;\nimport static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static rx.Notification.Kind.OnError;\nimport static rx.Notification.Kind.OnNext;\nimport static rx.Observable.fromCallable;\n\n@Ignore\npublic class Testing {\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tTestScheduler sched = Schedulers.test();\n\t\tObservable<String> fast = Observable\n\t\t\t\t.interval(10, MILLISECONDS, sched)\n\t\t\t\t.map(x -> \"F\" + x)\n\t\t\t\t.take(3);\n\t\tObservable<String> slow = Observable\n\t\t\t\t.interval(50, MILLISECONDS, sched)\n\t\t\t\t.map(x -> \"S\" + x);\n\n\t\tObservable<String> stream = Observable.concat(fast, slow);\n\t\tstream.subscribe(System.out::println);\n\t\tSystem.out.println(\"Subscribed\");\n\t}\n\n\t@Test\n\tpublic void sample_31() throws Exception {\n\t\tTestScheduler sched = Schedulers.test();\n\n\t\tTimeUnit.SECONDS.sleep(1);\n\t\tSystem.out.println(\"After one second\");\n\t\tsched.advanceTimeBy(25, MILLISECONDS);\n\n\t\tTimeUnit.SECONDS.sleep(1);\n\t\tSystem.out.println(\"After one more second\");\n\t\tsched.advanceTimeBy(75, MILLISECONDS);\n\n\t\tTimeUnit.SECONDS.sleep(1);\n\t\tSystem.out.println(\"...and one more\");\n\t\tsched.advanceTimeTo(200, MILLISECONDS);\n\t}\n\n\t@Test\n\tpublic void shouldApplyConcatMapInOrder() throws Exception {\n\t\tList<String> list = Observable\n\t\t\t\t.range(1, 3)\n\t\t\t\t.concatMap(x -> Observable.just(x, -x))\n\t\t\t\t.map(Object::toString)\n\t\t\t\t.toList()\n\t\t\t\t.toBlocking()\n\t\t\t\t.single();\n\n\t\tassertThat(list).containsExactly(\"1\", \"-1\", \"2\", \"-2\", \"3\", \"-3\");\n\t}\n\n\t@Test\n\tpublic void sample_65() throws Exception {\n\t\tFile file = new File(\"404.txt\");\n\t\tBlockingObservable<String> fileContents =\n\t\t\t\tfromCallable(() -> Files.toString(file, UTF_8))\n\t\t\t\t.toBlocking();\n\n\t\ttry {\n\t\t\tfileContents.single();\n\t\t\tfailBecauseExceptionWasNotThrown(FileNotFoundException.class);\n\t\t} catch (RuntimeException expected) {\n\t\t\tassertThat(expected)\n\t\t\t\t\t.hasCauseInstanceOf(FileNotFoundException.class);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void sample_87() throws Exception {\n\t\tObservable<Notification<Integer>> notifications = Observable\n\t\t\t\t.just(3, 0, 2, 0, 1, 0)\n\t\t\t\t.concatMapDelayError(x -> fromCallable(() -> 100 / x))\n\t\t\t\t.materialize();\n\n\t\tList<Notification.Kind> kinds = notifications\n\t\t\t\t.map(Notification::getKind)\n\t\t\t\t.toList()\n\t\t\t\t.toBlocking()\n\t\t\t\t.single();\n\n\t\tassertThat(kinds).containsExactly(OnNext, OnNext, OnNext, OnError);\n\t}\n\n\t@Test\n\tpublic void sample_107() throws Exception {\n\t\tObservable<Integer> obs = Observable\n\t\t\t\t.just(3, 0, 2, 0, 1, 0)\n\t\t\t\t.concatMapDelayError(x -> Observable.fromCallable(() -> 100 / x));\n\n\t\tTestSubscriber<Integer> ts = new TestSubscriber<>();\n\t\tobs.subscribe(ts);\n\n\t\tts.assertValues(33, 50, 100);\n\t\tts.assertError(ArithmeticException.class);  //Fails (!)\n\t}\n\n\tprivate MyServiceWithTimeout mockReturning(\n\t\t\tObservable<LocalDate> result,\n\t\t\tTestScheduler testScheduler) {\n\t\tMyService mock = mock(MyService.class);\n\t\tgiven(mock.externalCall()).willReturn(result);\n\t\treturn new MyServiceWithTimeout(mock, testScheduler);\n\t}\n\n\t@Test\n\tpublic void timeoutWhenServiceNeverCompletes() throws Exception {\n\t\t//given\n\t\tTestScheduler testScheduler = Schedulers.test();\n\t\tMyService mock = mockReturning(\n\t\t\t\tObservable.never(), testScheduler);\n\t\tTestSubscriber<LocalDate> ts = new TestSubscriber<>();\n\n\t\t//when\n\t\tmock.externalCall().subscribe(ts);\n\n\t\t//then\n\t\ttestScheduler.advanceTimeBy(950, MILLISECONDS);\n\t\tts.assertNoTerminalEvent();\n\t\ttestScheduler.advanceTimeBy(100, MILLISECONDS);\n\t\tts.assertCompleted();\n\t\tts.assertNoValues();\n\t}\n\n\t@Test\n\tpublic void valueIsReturnedJustBeforeTimeout() throws Exception {\n\t\t//given\n\t\tTestScheduler testScheduler = Schedulers.test();\n\t\tObservable<LocalDate> slow = Observable\n\t\t\t\t.timer(950, MILLISECONDS, testScheduler)\n\t\t\t\t.map(x -> LocalDate.now());\n\t\tMyService myService = mockReturning(slow, testScheduler);\n\t\tTestSubscriber<LocalDate> ts = new TestSubscriber<>();\n\n\t\t//when\n\t\tmyService.externalCall().subscribe(ts);\n\n\t\t//then\n\t\ttestScheduler.advanceTimeBy(930, MILLISECONDS);\n\t\tts.assertNotCompleted();\n\t\tts.assertNoValues();\n\t\ttestScheduler.advanceTimeBy(50, MILLISECONDS);\n\t\tts.assertCompleted();\n\t\tts.assertValueCount(1);\n\t}\n\n\tprivate final TestScheduler testScheduler = new TestScheduler();\n\n\t@Before\n\tpublic void alwaysUseTestScheduler() {\n\t\tRxJavaPlugins\n\t\t\t\t.getInstance()\n\t\t\t\t.registerSchedulersHook(new RxJavaSchedulersHook() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Scheduler getComputationScheduler() {\n\t\t\t\t\t\treturn testScheduler;\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Scheduler getIOScheduler() {\n\t\t\t\t\t\treturn testScheduler;\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Scheduler getNewThreadScheduler() {\n\t\t\t\t\t\treturn testScheduler;\n\t\t\t\t\t}\n\t\t\t\t});\n\t}\n\n\tObservable<Long> naturals1() {\n\t\treturn Observable.create(subscriber -> {\n\t\t\tlong i = 0;\n\t\t\twhile (!subscriber.isUnsubscribed()) {\n\t\t\t\tsubscriber.onNext(i++);\n\t\t\t}\n\t\t});\n\t}\n\n\tObservable<Long> naturals2() {\n\t\treturn Observable.create(\n\t\t\t\tSyncOnSubscribe.createStateful(\n\t\t\t\t\t\t() -> 0L,\n\t\t\t\t\t\t(cur, observer) -> {\n\t\t\t\t\t\t\tobserver.onNext(cur);\n\t\t\t\t\t\t\treturn cur + 1;\n\t\t\t\t\t\t}\n\t\t\t\t));\n\t}\n\n\t@Test\n\tpublic void sample_222() throws Exception {\n\t\tTestSubscriber<Long> ts = new TestSubscriber<>(0);\n\n\t\tnaturals1()\n\t\t\t\t.take(10)\n\t\t\t\t.subscribe(ts);\n\n\t\tts.assertNoValues();\n\t\tts.requestMore(100);\n\t\tts.assertValueCount(10);\n\t\tts.assertCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch7/TrackingId.java",
    "content": "package com.oreilly.rxjava.ch7;\n\nclass TrackingId {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Android.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport android.app.Activity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.*;\nimport com.oreilly.rxjava.ch8.rxandroid.AndroidSchedulers;\nimport com.oreilly.rxjava.ch8.rxbinding.RxTextView;\nimport com.oreilly.rxjava.ch8.rxbinding.RxView;\nimport com.oreilly.rxjava.ch8.rxbinding.TextViewAfterTextChangeEvent;\nimport org.apache.commons.lang3.tuple.Pair;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.functions.Action1;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.schedulers.Schedulers;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport static android.content.ContentValues.TAG;\n\n@Ignore\npublic class Android extends Activity {\n\n\tprivate final MeetupApi meetup = new ApiFactory().meetup();\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tButton button = null;  //...\n\t\tbutton.setOnClickListener(new View.OnClickListener() {\n\t\t\t@Override\n\t\t\tpublic void onClick(View view) {\n\t\t\t\tmeetup\n\t\t\t\t\t\t.listCities(52.229841, 21.011736)\n\t\t\t\t\t\t.concatMapIterable(extractCities())\n\t\t\t\t\t\t.map(toCityName())\n\t\t\t\t\t\t.toList()\n\t\t\t\t\t\t.subscribeOn(Schedulers.io())\n\t\t\t\t\t\t.observeOn(AndroidSchedulers.mainThread())\n\t\t\t\t\t\t.subscribe(\n\t\t\t\t\t\t\t\tputOnListView(),\n\t\t\t\t\t\t\t\tdisplayError());\n\t\t\t}\n\n\t\t\t//...\n\n\t\t});\n\t}\n\n\t//Cities::getResults\n\tFunc1<Cities, Iterable<City>> extractCities() {\n\t\treturn new Func1<Cities, Iterable<City>>() {\n\t\t\t@Override\n\t\t\tpublic Iterable<City> call(Cities cities) {\n\t\t\t\treturn cities.getResults();\n\t\t\t}\n\t\t};\n\t}\n\n\t//City::getCity\n\tFunc1<City, String> toCityName() {\n\t\treturn new Func1<City, String>() {\n\t\t\t@Override\n\t\t\tpublic String call(City city) {\n\t\t\t\treturn city.getCity();\n\t\t\t}\n\t\t};\n\t}\n\n\t//cities -> listView.setAdapter(...)\n\tAction1<List<String>> putOnListView() {\n\t\tListView listView = null; //...\n\t\treturn new Action1<List<String>>() {\n\t\t\t@Override\n\t\t\tpublic void call(List<String> cities) {\n\t\t\t\tlistView.setAdapter(new ArrayAdapter(Android.this, -1 /*R.layout.list*/, cities));\n\t\t\t}\n\t\t};\n\t}\n\n\t//throwable -> {...}\n\tAction1<Throwable> displayError() {\n\t\treturn new Action1<Throwable>() {\n\t\t\t@Override\n\t\t\tpublic void call(Throwable throwable) {\n\t\t\t\tLog.e(TAG, \"Error\", throwable);\n\t\t\t\tToast.makeText(Android.this, \"Unable to load cities\", Toast.LENGTH_SHORT).show();\n\t\t\t}\n\t\t};\n\t}\n\n\t@Test\n\tpublic void sample_98() throws Exception {\n\t\tButton button = new Button(null);\n\t\tRxView\n\t\t\t\t.clicks(button)\n\t\t\t\t.flatMap(c -> meetup.listCities(52.229841, 21.011736))\n\t\t\t\t.delay(2, TimeUnit.SECONDS)\n\t\t\t\t.concatMapIterable(extractCities())\n\t\t\t\t.map(toCityName())\n\t\t\t\t.toList()\n\t\t\t\t.subscribeOn(Schedulers.io())\n\t\t\t\t.observeOn(AndroidSchedulers.mainThread())\n\t\t\t\t.subscribe(\n\t\t\t\t\t\tputOnListView(),\n\t\t\t\t\t\tdisplayError());\n\t}\n\n\tFunc1<Void, Observable<Cities>> listCities(final double lat, final double lon) {\n\t\treturn new Func1<Void, Observable<Cities>>() {\n\t\t\t@Override\n\t\t\tpublic Observable<Cities> call(Void aVoid) {\n\t\t\t\treturn meetup.listCities(lat, lon);\n\t\t\t}\n\t\t};\n\t}\n\n\t@Test\n\tpublic void sample_121() throws Exception {\n\t\tEditText latText = null;//...\n\t\tEditText lonText = null;//...\n\n\t\tObservable<Double> latChanges = RxTextView\n\t\t\t\t.afterTextChangeEvents(latText)\n\t\t\t\t.flatMap(toDouble());\n\t\tObservable<Double> lonChanges = RxTextView\n\t\t\t\t.afterTextChangeEvents(lonText)\n\t\t\t\t.flatMap(toDouble());\n\n\t\tObservable<Cities> cities = Observable\n\t\t\t\t.combineLatest(latChanges, lonChanges, toPair())\n\t\t\t\t.debounce(1, TimeUnit.SECONDS)\n\t\t\t\t.flatMap(listCitiesNear());\n\t}\n\n\tFunc1<TextViewAfterTextChangeEvent, Observable<Double>> toDouble() {\n\t\treturn new Func1<TextViewAfterTextChangeEvent, Observable<Double>>() {\n\t\t\t@Override\n\t\t\tpublic Observable<Double> call(TextViewAfterTextChangeEvent e) {\n\t\t\t\tString s = e.editable().toString();\n\t\t\t\ttry {\n\t\t\t\t\treturn Observable.just(Double.parseDouble(s));\n\t\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\t\treturn Observable.empty();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t//return Pair::new\n\tFunc2<Double, Double, Pair<Double, Double>> toPair() {\n\t\treturn new Func2<Double, Double, Pair<Double, Double>>() {\n\t\t\t@Override\n\t\t\tpublic Pair<Double, Double> call(Double lat, Double lon) {\n\t\t\t\treturn Pair.of(lat, lon);\n\t\t\t}\n\t\t};\n\t}\n\n\t//return latLon -> meetup.listCities(latLon.first, latLon.second)\n\tFunc1<Pair<Double, Double>, Observable<Cities>> listCitiesNear() {\n\t\treturn new Func1<Pair<Double, Double>, Observable<Cities>>() {\n\t\t\t@Override\n\t\t\tpublic Observable<Cities> call(Pair<Double, Double> latLon) {\n\t\t\t\treturn meetup.listCities(latLon.getLeft(), latLon.getRight());\n\t\t\t}\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/ApiFactory.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.PropertyNamingStrategy;\nimport retrofit2.Retrofit;\nimport retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;\nimport retrofit2.converter.jackson.JacksonConverterFactory;\n\nclass ApiFactory {\n\n\tGeoNames geoNames() {\n\t\treturn new Retrofit.Builder()\n\t\t\t\t.baseUrl(\"http://api.geonames.org\")\n\t\t\t\t.addCallAdapterFactory(RxJavaCallAdapterFactory.create())\n\t\t\t\t.addConverterFactory(JacksonConverterFactory.create(objectMapper()))\n\t\t\t\t.build()\n\t\t\t\t.create(GeoNames.class);\n\t}\n\n\tMeetupApi meetup() {\n\t\tRetrofit retrofit = new Retrofit.Builder()\n\t\t\t\t.baseUrl(\"https://api.meetup.com/\")\n\t\t\t\t.addCallAdapterFactory(\n\t\t\t\t\t\tRxJavaCallAdapterFactory.create())\n\t\t\t\t.addConverterFactory(\n\t\t\t\t\t\tJacksonConverterFactory.create(objectMapper()))\n\t\t\t\t.build();\n\t\treturn retrofit.create(MeetupApi.class);\n\t}\n\n\tprivate ObjectMapper objectMapper() {\n\t\tObjectMapper objectMapper = new ObjectMapper();\n\t\tobjectMapper.setPropertyNamingStrategy(\n\t\t\t\tPropertyNamingStrategy.SNAKE_CASE);\n\t\tobjectMapper.configure(\n\t\t\t\tDeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);\n\t\treturn objectMapper;\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Chapter8.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport com.couchbase.client.java.CouchbaseAsyncCluster;\nimport com.couchbase.client.java.document.AbstractDocument;\nimport com.couchbase.client.java.document.json.JsonArray;\nimport com.mongodb.client.model.Filters;\nimport com.mongodb.client.model.Projections;\nimport com.mongodb.rx.client.MongoClients;\nimport com.mongodb.rx.client.MongoCollection;\nimport com.mongodb.rx.client.MongoDatabase;\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Message;\nimport org.apache.camel.impl.DefaultCamelContext;\nimport org.apache.camel.rx.ReactiveCamel;\nimport org.bson.Document;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport rx.Observable;\n\nimport java.math.BigDecimal;\nimport java.time.Instant;\nimport java.time.LocalDateTime;\nimport java.time.Month;\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\n\nimport static com.oreilly.rxjava.ch8.GeoNames.log;\nimport static java.time.Month.APRIL;\nimport static java.util.concurrent.TimeUnit.MICROSECONDS;\nimport static java.util.stream.Collectors.toList;\n\n\n@Ignore\npublic class Chapter8 {\n\n\t@Test\n\tpublic void sample_9() throws Exception {\n\t\tfinal ApiFactory api = new ApiFactory();\n\t\tMeetupApi meetup = api.meetup();\n\t\tGeoNames geoNames = api.geoNames();\n\n\t\tdouble warsawLat = 52.229841;\n\t\tdouble warsawLon = 21.011736;\n\t\tObservable<Cities> cities = meetup.listCities(warsawLat, warsawLon);\n\t\tObservable<City> cityObs = cities.concatMapIterable(Cities::getResults);\n\n\t\tObservable<String> map = cityObs\n\t\t\t\t.filter(city -> city.distanceTo(warsawLat, warsawLon) < 50)\n\t\t\t\t.map(City::getCity);\n\n\t\tObservable<Long> totalPopulation = meetup\n\t\t\t\t.listCities(warsawLat, warsawLon)\n\t\t\t\t.concatMapIterable(Cities::getResults)\n\t\t\t\t.filter(city -> city.distanceTo(warsawLat, warsawLon) < 50)\n\t\t\t\t.map(City::getCity)\n\t\t\t\t.flatMap(geoNames::populationOf)\n\t\t\t\t.reduce(0L, (x, y) -> x + y);\n\t}\n\n\t@Test\n\tpublic void sample_35() throws Exception {\n\t\tCouchbaseAsyncCluster cluster = CouchbaseAsyncCluster.create();\n\t\tcluster\n\t\t\t\t.openBucket(\"travel-sample\")\n\t\t\t\t.flatMap(cl -> cl.get(\"route_14197\")\n\t\t\t\t\t\t.map(AbstractDocument::content)\n\t\t\t\t\t\t.map(jsonObject -> jsonObject.getArray(\"schedule\")))\n\t\t\t\t.concatMapIterable(JsonArray::toList)\n\t\t\t\t.cast(Map.class)\n\t\t\t\t.filter(m -> ((Number) m.get(\"day\")).intValue() == 0)\n\t\t\t\t.map(m -> m.get(\"flight\").toString())\n\t\t\t\t.subscribe(flight -> System.out.println(flight));\n\t}\n\n\t@Test\n\tpublic void sample_55() throws Exception {\n\t\tMongoCollection<Document> monthsColl = com.mongodb.rx.client.MongoClients\n\t\t\t\t.create()\n\t\t\t\t.getDatabase(\"rx\")\n\t\t\t\t.getCollection(\"months\");\n\n\t\tObservable\n\t\t\t\t.from(Month.values())\n\t\t\t\t.map(month -> new Document()\n\t\t\t\t\t\t.append(\"name\", month.name())\n\t\t\t\t\t\t.append(\"days_not_leap\", month.length(false))\n\t\t\t\t\t\t.append(\"days_leap\", month.length(true))\n\t\t\t\t)\n\t\t\t\t.toList()\n\t\t\t\t.flatMap(monthsColl::insertMany)\n\t\t\t\t.flatMap(s -> monthsColl.find().toObservable())\n\t\t\t\t.toBlocking()\n\t\t\t\t.subscribe(System.out::println);\n\n\t}\n\n\t@Test\n\tpublic void sample_105() throws Exception {\n\t\tfinal MongoDatabase db = MongoClients\n\t\t\t\t.create()\n\t\t\t\t.getDatabase(\"rx\");\n\n\t\tObservable<Integer> days = db.getCollection(\"months\")\n\t\t\t\t.find(Filters.eq(\"name\", APRIL.name()))\n\t\t\t\t.projection(Projections.include(\"days_not_leap\"))\n\t\t\t\t.first()\n\t\t\t\t.map(doc -> doc.getInteger(\"days_not_leap\"));\n\t\tObservable<Instant> carManufactured = db.getCollection(\"cars\")\n\t\t\t\t.find(Filters.eq(\"owner.name\", \"Smith\"))\n\t\t\t\t.first()\n\t\t\t\t.map(doc -> doc.getDate(\"manufactured\"))\n\t\t\t\t.map(Date::toInstant);\n\n\t\tObservable<BigDecimal> pricePerDay = dailyPrice(LocalDateTime.now());\n\t\tObservable<Insurance> insurance = Observable\n\t\t\t\t.zip(days, carManufactured, pricePerDay,\n\t\t\t\t\t\t(d, man, price) -> {\n\t\t\t\t\t\t\t//Create insurance\n\t\t\t\t\t\t\treturn new Insurance();\n\t\t\t\t\t\t});\n\t}\n\n\tprivate Observable<BigDecimal> dailyPrice(LocalDateTime date) {\n\t\treturn Observable.just(BigDecimal.TEN);\n\t}\n\n\t@Test\n\tpublic void sample_121() throws Exception {\n\t\tCamelContext camel = new DefaultCamelContext();\n\t\tReactiveCamel reactiveCamel = new ReactiveCamel(camel);\n\n\t\treactiveCamel\n\t\t\t\t.toObservable(\"file:/home/user/tmp\")\n\t\t\t\t.subscribe(e ->\n\t\t\t\t\t\tlog.info(\"New file: {}\", e));\n\t}\n\n\t@Test\n\tpublic void sample_136() throws Exception {\n\t\tCamelContext camel = new DefaultCamelContext();\n\t\tReactiveCamel reactiveCamel = new ReactiveCamel(camel);\n\t\treactiveCamel\n\t\t\t\t.toObservable(\"kafka:localhost:9092?topic=demo&groupId=rx\")\n\t\t\t\t.map(Message::getBody)\n\t\t\t\t.subscribe(e ->\n\t\t\t\t\t\tlog.info(\"Message: {}\", e));\n\t}\n\n\t@Test\n\tpublic void sample_148() throws Exception {\n\t\tList<Person> people = Collections.emptyList(); //...\n\n\t\tList<String> sorted = people\n\t\t\t\t.parallelStream()\n\t\t\t\t.filter(p -> p.getAge() >= 18)\n\t\t\t\t.map(Person::getFirstName)\n\t\t\t\t.sorted(Comparator.comparing(String::toLowerCase))\n\t\t\t\t.collect(toList());\n\n\t\t//DON'T DO THIS\n\t\tpeople\n\t\t\t\t.parallelStream()\n\t\t\t\t.forEach(this::publishOverJms);\n\t}\n\n\tprivate void publishOverJms(Person person) {\n\t\t//...\n\t}\n\n\t@Test\n\tpublic void sample_170() throws Exception {\n\t\tObservable\n\t\t\t\t.range(0, Integer.MAX_VALUE)\n\t\t\t\t.map(Picture::new)\n\t\t\t\t.distinct()\n\t\t\t\t.distinct(Picture::getTag)\n\t\t\t\t.sample(1, TimeUnit.SECONDS)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_182() throws Exception {\n\t\tObservable\n\t\t\t\t.range(0, Integer.MAX_VALUE)\n\t\t\t\t.map(Picture::new)\n\t\t\t\t.window(1, TimeUnit.SECONDS)\n\t\t\t\t.flatMap(Observable::count)\n\t\t\t\t.subscribe(System.out::println);\n\t}\n\n\t@Test\n\tpublic void sample_192() throws Exception {\n\t\tObservable\n\t\t\t\t.range(0, Integer.MAX_VALUE)\n\t\t\t\t.map(Picture::new)\n\t\t\t\t.window(10, TimeUnit.SECONDS)\n\t\t\t\t.flatMap(Observable::distinct);\n\t}\n\n\t@Test\n\tpublic void sample_201() throws Exception {\n\t\tObservable<Incident> incidents = Observable.empty(); //...\n\n\t\tObservable<Boolean> danger = incidents\n\t\t\t\t.buffer(1, TimeUnit.SECONDS)\n\t\t\t\t.map((List<Incident> oneSecond) -> oneSecond\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.filter(Incident::isHIghPriority)\n\t\t\t\t\t\t.count() > 5);\n\t}\n\n\t@Test\n\tpublic void sample_213() throws Exception {\n\t\tObservable<Picture> fast = Observable\n\t\t\t\t.interval(10, MICROSECONDS)\n\t\t\t\t.map(Picture::new);\n\t\tObservable<Picture> slow = Observable\n\t\t\t\t.interval(11, MICROSECONDS)\n\t\t\t\t.map(Picture::new);\n\n\t\tObservable\n\t\t\t\t.zip(fast, slow, (f, s) -> f + \" : \" + s);\n\n\t\tObservable\n\t\t\t\t.zip(\n\t\t\t\t\t\tfast.onBackpressureDrop(),\n\t\t\t\t\t\tslow.onBackpressureDrop(),\n\t\t\t\t\t\t(f, s) -> f + \" : \" + s);\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Cities.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport java.util.List;\n\npublic class Cities {\n    private List<City> results;\n\n    public List<City> getResults() {\n        return results;\n    }\n\n    public void setResults(List<City> results) {\n        this.results = results;\n    }\n}\n\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/City.java",
    "content": "package com.oreilly.rxjava.ch8;\n\npublic class City {\n    private String city;\n    private String country;\n    private Double distance;\n    private Integer id;\n    private Double lat;\n    private String localizedCountryName;\n    private Double lon;\n    private Integer memberCount;\n    private Integer ranking;\n    private String zip;\n\n    public String getCity() {\n        return city;\n    }\n\n    public void setCity(String city) {\n        this.city = city;\n    }\n\n    public String getCountry() {\n        return country;\n    }\n\n    public void setCountry(String country) {\n        this.country = country;\n    }\n\n    public Double getDistance() {\n        return distance;\n    }\n\n    public void setDistance(Double distance) {\n        this.distance = distance;\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public Double getLat() {\n        return lat;\n    }\n\n    public void setLat(Double lat) {\n        this.lat = lat;\n    }\n\n    public String getLocalizedCountryName() {\n        return localizedCountryName;\n    }\n\n    public void setLocalizedCountryName(String localizedCountryName) {\n        this.localizedCountryName = localizedCountryName;\n    }\n\n    public Double getLon() {\n        return lon;\n    }\n\n    public void setLon(Double lon) {\n        this.lon = lon;\n    }\n\n    public Integer getMemberCount() {\n        return memberCount;\n    }\n\n    public void setMemberCount(Integer memberCount) {\n        this.memberCount = memberCount;\n    }\n\n    public Integer getRanking() {\n        return ranking;\n    }\n\n    public void setRanking(Integer ranking) {\n        this.ranking = ranking;\n    }\n\n    public String getZip() {\n        return zip;\n    }\n\n    public void setZip(String zip) {\n        this.zip = zip;\n    }\n\n    public double distanceTo(double lat, double lon) {\n        //TODO Use correct formula\n        return 0.0;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/GeoNames.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport retrofit2.http.GET;\nimport retrofit2.http.Query;\nimport rx.Observable;\nimport rx.schedulers.Schedulers;\n\npublic interface GeoNames {\n\n    Logger log = LoggerFactory.getLogger(GeoNames.class);\n\n    default Observable<Integer> populationOf(String query) {\n        return search(query)\n                .concatMapIterable(SearchResult::getGeonames)\n                .map(Geoname::getPopulation)\n                .filter(p -> p != null)\n                .singleOrDefault(0)\n                .doOnError(th ->\n                        log.warn(\"Falling back to 0 for {}\", query, th))\n                .onErrorReturn(th -> 0)\n                .subscribeOn(Schedulers.io());\n    }\n\n    default Observable<SearchResult> search(String query) {\n        return search(query, 1, \"LONG\", \"some_user\");\n    }\n\n    @GET(\"/searchJSON\")\n    Observable<SearchResult> search(\n            @Query(\"q\") String query,\n            @Query(\"maxRows\") int maxRows,\n            @Query(\"style\") String style,\n            @Query(\"username\") String username\n    );\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Geoname.java",
    "content": "package com.oreilly.rxjava.ch8;\n\npublic class Geoname {\n    private String lat;\n    private String lng;\n    private Integer geonameId;\n    private Integer population;\n    private String countryCode;\n    private String name;\n\n    public String getLat() {\n        return lat;\n    }\n\n    public void setLat(String lat) {\n        this.lat = lat;\n    }\n\n    public String getLng() {\n        return lng;\n    }\n\n    public void setLng(String lng) {\n        this.lng = lng;\n    }\n\n    public Integer getGeonameId() {\n        return geonameId;\n    }\n\n    public void setGeonameId(Integer geonameId) {\n        this.geonameId = geonameId;\n    }\n\n    public Integer getPopulation() {\n        return population;\n    }\n\n    public void setPopulation(Integer population) {\n        this.population = population;\n    }\n\n    public String getCountryCode() {\n        return countryCode;\n    }\n\n    public void setCountryCode(String countryCode) {\n        this.countryCode = countryCode;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Incident.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nclass Incident {\n\tboolean isHIghPriority() {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Insurance.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nclass Insurance {\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/MeetupApi.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport retrofit2.http.GET;\nimport retrofit2.http.Query;\nimport rx.Observable;\n\n\npublic interface MeetupApi {\n\n    @GET(\"/2/cities\")\n    Observable<Cities> listCities(\n\t\t@Query(\"lat\") double lat,\n\t\t@Query(\"lon\") double lon\n    );\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Person.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nclass Person {\n\n\tint getAge() {\n\t\treturn 42;\n\t}\n\n\tString getFirstName() {\n\t\treturn \"Smith\";\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/Picture.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nclass Picture {\n    private final byte[] blob = new byte[128 * 1024];\n    private final long tag;\n\n    Picture(long tag) { this.tag = tag; }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof Picture)) return false;\n        Picture picture = (Picture) o;\n        return tag == picture.tag;\n    }\n\n    long getTag() {\n        return tag;\n    }\n\n    @Override\n    public int hashCode() {\n        return (int) (tag ^ (tag >>> 32));\n    }\n\n    @Override\n    public String toString() {\n        return Long.toString(tag);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/SearchResult.java",
    "content": "package com.oreilly.rxjava.ch8;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nclass SearchResult {\n    private List<Geoname> geonames = new ArrayList<>();\n\n    public List<Geoname> getGeonames() {\n        return geonames;\n    }\n\n    public void setGeonames(List<Geoname> geonames) {\n        this.geonames = geonames;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/hystrix/BlockingCmd.java",
    "content": "package com.oreilly.rxjava.ch8.hystrix;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\n\nclass BlockingCmd extends HystrixCommand<String> {\n\n\tpublic BlockingCmd() {\n\t\tsuper(HystrixCommandGroupKey.Factory.asKey(\"SomeGroup\"));\n\t}\n\n\t@Override\n\tprotected String run() throws IOException {\n\t\tfinal URL url = new URL(\"http://www.example.com\");\n\t\ttry (InputStream input = url.openStream()) {\n\t\t\treturn IOUtils.toString(input, StandardCharsets.UTF_8);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/hystrix/Book.java",
    "content": "package com.oreilly.rxjava.ch8.hystrix;\n\nclass Book {\n}\n\nclass Rating {\n\n\tprivate final Book book;\n\n\tRating(Book book) {\n\t\tthis.book = book;\n\t}\n\n\tpublic Book getBook() {\n\t\treturn book;\n\t}\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/hystrix/CitiesCmd.java",
    "content": "package com.oreilly.rxjava.ch8.hystrix;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.oreilly.rxjava.ch8.Cities;\nimport com.oreilly.rxjava.ch8.MeetupApi;\nimport rx.Observable;\n\nclass CitiesCmd extends HystrixObservableCommand<Cities> {\n\n    private final MeetupApi api;\n    private final double lat;\n    private final double lon;\n\n    protected CitiesCmd(MeetupApi api, double lat, double lon) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"Meetup\"));\n        this.api = api;\n        this.lat = lat;\n        this.lon = lon;\n    }\n\n    @Override\n    protected Observable<Cities> construct() {\n        return api.listCities(lat, lon);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/hystrix/FetchManyRatings.java",
    "content": "package com.oreilly.rxjava.ch8.hystrix;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport rx.Observable;\n\nimport java.util.Collection;\n\nclass FetchManyRatings extends HystrixObservableCommand<Rating> {\n\n    private final Collection<Book> books;\n\n    protected FetchManyRatings(Collection<Book> books) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"Books\"));\n        this.books = books;\n    }\n\n    @Override\n    protected Observable<Rating> construct() {\n        return fetchManyRatings(books);\n    }\n\n    private Observable<Rating> fetchManyRatings(Collection<Book> books) {\n        return Observable\n                .from(books)\n                .map(Rating::new);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/hystrix/FetchRatingsCollapser.java",
    "content": "package com.oreilly.rxjava.ch8.hystrix;\n\nimport com.netflix.hystrix.*;\nimport rx.functions.Func1;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport static com.netflix.hystrix.HystrixObservableCollapser.Setter.withCollapserKey;\nimport static java.util.stream.Collectors.toList;\n\npublic class FetchRatingsCollapser\n\textends HystrixObservableCollapser<Book, Rating, Rating, Book> {\n\n    private final Book book;\n\n    public FetchRatingsCollapser(Book book) {\n        super(withCollapserKey(HystrixCollapserKey.Factory.asKey(\"Books\"))\n                .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter()\n                        .withTimerDelayInMilliseconds(20)\n                        .withMaxRequestsInBatch(50)\n                )\n                .andScope(Scope.GLOBAL));\n        this.book = book;\n    }\n\n    public Book getRequestArgument() {\n        return book;\n    }\n\n    protected HystrixObservableCommand<Rating> createCommand(\n    \t\tCollection<HystrixCollapser.CollapsedRequest<Rating, Book>> requests) {\n        List<Book> books = requests.stream()\n                .map(c -> c.getArgument())\n                .collect(toList());\n        return new FetchManyRatings(books);\n    }\n\n    protected void onMissingResponse(HystrixCollapser.CollapsedRequest<Rating, Book> r) {\n        r.setException(new RuntimeException(\"Not found for: \" + r.getArgument()));\n    }\n\n    protected Func1<Book, Book> getRequestArgumentKeySelector() {\n        return x -> x;\n    }\n\n    protected Func1<Rating, Rating> getBatchReturnTypeToResponseTypeMapper() {\n        return x -> x;\n    }\n\n    protected Func1<Rating, Book> getBatchReturnTypeKeySelector() {\n        return Rating::getBook;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/hystrix/Hystrix.java",
    "content": "package com.oreilly.rxjava.ch8.hystrix;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;\nimport com.netflix.hystrix.metric.HystrixCommandCompletionStream;\nimport com.oreilly.rxjava.ch8.Cities;\nimport com.oreilly.rxjava.ch8.MeetupApi;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.servlet.ServletContextHandler;\nimport org.eclipse.jetty.servlet.ServletHolder;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\n\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\nimport static com.netflix.hystrix.HystrixEventType.FAILURE;\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static org.eclipse.jetty.servlet.ServletContextHandler.NO_SESSIONS;\nimport static org.mockito.ArgumentMatchers.anyDouble;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@Ignore\npublic class Hystrix {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Hystrix.class);\n\n\t@Test\n\tpublic void sample_17() throws Exception {\n\t\tString string = new BlockingCmd().execute();\n\t\tFuture<String> future = new BlockingCmd().queue();\n\t\tObservable<String> eager = new BlockingCmd().observe();\n\t\tObservable<String> lazy = new BlockingCmd().toObservable();\n\t}\n\n\t@Test\n\tpublic void sample_28() throws Exception {\n\t\tObservable<String> retried = new BlockingCmd()\n\t\t\t\t.toObservable()\n\t\t\t\t.doOnError(ex -> log.warn(\"Error \", ex))\n\t\t\t\t.retryWhen(ex -> ex.delay(500, MILLISECONDS))\n\t\t\t\t.timeout(3, SECONDS);\n\t}\n\n\t@Test\n\tpublic void sample_44() throws Exception {\n\t\tMeetupApi api = mock(MeetupApi.class);\n\t\tgiven(api.listCities(anyDouble(), anyDouble())).willReturn(\n\t\t\t\tObservable\n\t\t\t\t\t\t.<Cities>error(new RuntimeException(\"Broken\"))\n\t\t\t\t\t\t.doOnSubscribe(() -> log.debug(\"Invoking\"))\n\t\t\t\t\t\t.delay(2, SECONDS)\n\t\t);\n\n\t\tObservable\n\t\t\t\t.interval(50, MILLISECONDS)\n\t\t\t\t.doOnNext(x -> log.debug(\"Requesting\"))\n\t\t\t\t.flatMap(x ->\n\t\t\t\t\t\t\t\tnew CitiesCmd(api, 52.229841, 21.011736)\n\t\t\t\t\t\t\t\t\t\t.toObservable()\n\t\t\t\t\t\t\t\t\t\t.onErrorResumeNext(ex -> Observable.empty()),\n\t\t\t\t\t\t5);\n\t}\n\n\tObservable<Book> allBooks() {\n\t\treturn Observable.just(new Book());\n\t}\n\tObservable<Rating> fetchRating(Book book) {\n\t\treturn Observable.just(new Rating(book));\n\t}\n\n\t@Test\n\tpublic void sample_69() throws Exception {\n\t\tObservable<Rating> ratings = allBooks()\n\t\t\t\t.flatMap(this::fetchRating);\n\t}\n\n\t@Test\n\tpublic void sample_83() throws Exception {\n\t\tfinal Book book = new Book();\n\t\tObservable<Rating> ratingObservable =\n\t\t\t\tnew FetchRatingsCollapser(book).toObservable();\n\t}\n\n\t@Test\n\tpublic void sample_82() throws Exception {\n\t\tHystrixCommandCompletionStream\n\t\t\t\t.getInstance(HystrixCommandKey.Factory.asKey(\"FetchRating\"))\n\t\t\t\t.observe()\n\t\t\t\t.filter(e -> e.getEventCounts().getCount(FAILURE) > 0)\n\t\t\t\t.window(1, TimeUnit.SECONDS)\n\t\t\t\t.flatMap(Observable::count)\n\t\t\t\t.subscribe(x -> log.info(\"{} failures/s\", x));\n\t}\n\n\t@Test\n\tpublic void sample_98() throws Exception {\n\t\tServletContextHandler context = new ServletContextHandler(NO_SESSIONS);\n\t\tHystrixMetricsStreamServlet servlet = new HystrixMetricsStreamServlet();\n\t\tcontext.addServlet(new ServletHolder(servlet), \"/hystrix.stream\");\n\t\tServer server = new Server(8080);\n\t\tserver.setHandler(context);\n\t\tserver.start();\n\t\tserver.join();\n\t}\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxandroid/AndroidSchedulers.java",
    "content": "/*\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.oreilly.rxjava.ch8.rxandroid;\n\nimport android.os.Looper;\nimport rx.Scheduler;\nimport rx.annotations.Experimental;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\n/** Android-specific Schedulers. */\npublic final class AndroidSchedulers {\n    private static final AtomicReference<AndroidSchedulers> INSTANCE = new AtomicReference<>();\n\n    private final Scheduler mainThreadScheduler;\n\n    private static AndroidSchedulers getInstance() {\n        for (;;) {\n            AndroidSchedulers current = INSTANCE.get();\n            if (current != null) {\n                return current;\n            }\n            current = new AndroidSchedulers();\n            if (INSTANCE.compareAndSet(null, current)) {\n                return current;\n            }\n        }\n    }\n\n    private AndroidSchedulers() {\n        RxAndroidSchedulersHook hook = RxAndroidPlugins.getInstance().getSchedulersHook();\n\n        Scheduler main = hook.getMainThreadScheduler();\n        if (main != null) {\n            mainThreadScheduler = main;\n        } else {\n            mainThreadScheduler = new LooperScheduler(Looper.getMainLooper());\n        }\n    }\n\n    /** A {@link Scheduler} which executes actions on the Android UI thread. */\n    public static Scheduler mainThread() {\n        return getInstance().mainThreadScheduler;\n    }\n\n    /** A {@link Scheduler} which executes actions on {@code looper}. */\n    public static Scheduler from(Looper looper) {\n        if (looper == null) throw new NullPointerException(\"looper == null\");\n        return new LooperScheduler(looper);\n    }\n\n    /**\n     * Resets the current {@link AndroidSchedulers} instance.\n     * This will re-init the cached schedulers on the next usage,\n     * which can be useful in testing.\n     */\n    @Experimental\n    public static void reset() {\n        INSTANCE.set(null);\n    }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxandroid/LooperScheduler.java",
    "content": "/*\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.oreilly.rxjava.ch8.rxandroid;\n\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport rx.Scheduler;\nimport rx.Subscription;\nimport rx.exceptions.OnErrorNotImplementedException;\nimport rx.functions.Action0;\nimport rx.plugins.RxJavaPlugins;\nimport rx.subscriptions.Subscriptions;\n\nimport java.util.concurrent.TimeUnit;\n\nclass LooperScheduler extends Scheduler {\n    private final Handler handler;\n\n    LooperScheduler(Looper looper) {\n        handler = new Handler(looper);\n    }\n\n    LooperScheduler(Handler handler) {\n        this.handler = handler;\n    }\n\n    @Override\n    public Worker createWorker() {\n        return new HandlerWorker(handler);\n    }\n\n    static class HandlerWorker extends Worker {\n        private final Handler handler;\n        private final RxAndroidSchedulersHook hook;\n        private volatile boolean unsubscribed;\n\n        HandlerWorker(Handler handler) {\n            this.handler = handler;\n            this.hook = RxAndroidPlugins.getInstance().getSchedulersHook();\n        }\n\n        @Override\n        public void unsubscribe() {\n            unsubscribed = true;\n            handler.removeCallbacksAndMessages(this /* token */);\n        }\n\n        @Override\n        public boolean isUnsubscribed() {\n            return unsubscribed;\n        }\n\n        @Override\n        public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {\n            if (unsubscribed) {\n                return Subscriptions.unsubscribed();\n            }\n\n            action = hook.onSchedule(action);\n\n            ScheduledAction scheduledAction = new ScheduledAction(action, handler);\n\n            Message message = Message.obtain(handler, scheduledAction);\n            message.obj = this; // Used as token for unsubscription operation.\n\n            handler.sendMessageDelayed(message, unit.toMillis(delayTime));\n\n            if (unsubscribed) {\n                handler.removeCallbacks(scheduledAction);\n                return Subscriptions.unsubscribed();\n            }\n\n            return scheduledAction;\n        }\n\n        @Override\n        public Subscription schedule(final Action0 action) {\n            return schedule(action, 0, TimeUnit.MILLISECONDS);\n        }\n    }\n\n    static final class ScheduledAction implements Runnable, Subscription {\n        private final Action0 action;\n        private final Handler handler;\n        private volatile boolean unsubscribed;\n\n        ScheduledAction(Action0 action, Handler handler) {\n            this.action = action;\n            this.handler = handler;\n        }\n\n        @Override public void run() {\n            try {\n                action.call();\n            } catch (Throwable e) {\n                // nothing to do but print a System error as this is fatal and there is nowhere else to throw this\n                IllegalStateException ie;\n                if (e instanceof OnErrorNotImplementedException) {\n                    ie = new IllegalStateException(\"Exception thrown on Scheduler.Worker thread. Add `onError` handling.\", e);\n                } else {\n                    ie = new IllegalStateException(\"Fatal Exception thrown on Scheduler.Worker thread.\", e);\n                }\n                RxJavaPlugins.getInstance().getErrorHandler().handleError(ie);\n                Thread thread = Thread.currentThread();\n                thread.getUncaughtExceptionHandler().uncaughtException(thread, ie);\n            }\n        }\n\n        @Override public void unsubscribe() {\n            unsubscribed = true;\n            handler.removeCallbacks(this);\n        }\n\n        @Override public boolean isUnsubscribed() {\n            return unsubscribed;\n        }\n    }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxandroid/MainActivity.java",
    "content": "package com.oreilly.rxjava.ch8.rxandroid;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.subscriptions.CompositeSubscription;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class MainActivity extends Activity {\n\n    private final byte[] blob = new byte[32 * 1024 * 1024];\n\n    private final CompositeSubscription allSubscriptions = new CompositeSubscription();\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        //...\n        Subscription subscription = Observable\n                .interval(100, TimeUnit.MILLISECONDS)\n                .observeOn(AndroidSchedulers.mainThread())\n                .subscribe(x -> {\n//                    text.setText(Long.toString(x));\n                });\n        allSubscriptions.add(subscription);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        allSubscriptions.unsubscribe();\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxandroid/MainThreadSubscription.java",
    "content": "/*\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.oreilly.rxjava.ch8.rxandroid;\n\nimport android.os.Looper;\nimport rx.Subscription;\nimport rx.functions.Action0;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * A {@linkplain Subscription subscription} which ensures its {@linkplain #onUnsubscribe()\n * unsubscribe action} is executed on the main thread. When unsubscription occurs on a different\n * thread than the main thread, the action is posted to run on the main thread as soon as possible.\n * <p>\n * Instances of this class are useful in creating observables which interact with APIs that can\n * only be used on the main thread, such as UI objects.\n * <p>\n * A {@link #verifyMainThread() convenience method} is also provided for validating whether code\n * is being called on the main thread. Calls to this method along with instances of this class are\n * commonly used when creating custom observables using the following pattern:\n * <pre><code>\n * &#064;Override public void call(Subscriber<? extends T> subscriber) {\n *   MainThreadSubscription.verifyMainThread();\n *\n *   // TODO set up behavior\n *\n *   subscriber.add(new MainThreadSubscription() {\n *     &#064;Override public void onUnsubscribe() {\n *       // TODO undo behavior\n *     }\n *   });\n * }\n * </code></pre>\n */\npublic abstract class MainThreadSubscription implements Subscription {\n  /**\n   * Verify that the calling thread is the Android main thread.\n   * <p>\n   * Calls to this method are usually preconditions for subscription behavior which instances of\n   * this class later undo. See the class documentation for an example.\n   *\n   * @throws IllegalStateException when called from any other thread.\n   */\n  public static void verifyMainThread() {\n    if (Looper.myLooper() != Looper.getMainLooper()) {\n      throw new IllegalStateException(\n          \"Expected to be called on the main thread but was \" + Thread.currentThread().getName());\n    }\n  }\n\n  private final AtomicBoolean unsubscribed = new AtomicBoolean();\n\n  @Override public final boolean isUnsubscribed() {\n    return unsubscribed.get();\n  }\n\n  @Override public final void unsubscribe() {\n    if (unsubscribed.compareAndSet(false, true)) {\n      if (Looper.myLooper() == Looper.getMainLooper()) {\n        onUnsubscribe();\n      } else {\n        AndroidSchedulers.mainThread().createWorker().schedule(new Action0() {\n          @Override public void call() {\n            onUnsubscribe();\n          }\n        });\n      }\n    }\n  }\n\n  protected abstract void onUnsubscribe();\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxandroid/RxAndroidPlugins.java",
    "content": "/*\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.oreilly.rxjava.ch8.rxandroid;\n\nimport rx.annotations.Experimental;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Registry for plugin implementations that allows global override and handles the retrieval of\n * correct implementation based on order of precedence:\n * <ol>\n * <li>plugin registered globally via {@code register} methods in this class</li>\n * <li>default implementation</li>\n * </ol>\n */\npublic final class RxAndroidPlugins {\n    private static final RxAndroidPlugins INSTANCE = new RxAndroidPlugins();\n\n    public static RxAndroidPlugins getInstance() {\n        return INSTANCE;\n    }\n\n    private final AtomicReference<RxAndroidSchedulersHook> schedulersHook = new AtomicReference<>();\n\n    RxAndroidPlugins() {\n    }\n\n    /**\n     * Reset any explicit or default-set hooks.\n     * <p>\n     * Note: This should only be used for testing purposes.\n     */\n    @Experimental\n    public void reset() {\n        schedulersHook.set(null);\n    }\n\n    /**\n     * Retrieves the instance of {@link RxAndroidSchedulersHook} to use based on order of\n     * precedence as defined in the {@link RxAndroidPlugins} class header.\n     * <p>\n     * Override the default by calling {@link #registerSchedulersHook(RxAndroidSchedulersHook)} or by\n     * setting the property {@code rxandroid.plugin.RxAndroidSchedulersHook.implementation} with the\n     * full classname to load.\n     */\n    public RxAndroidSchedulersHook getSchedulersHook() {\n        if (schedulersHook.get() == null) {\n            schedulersHook.compareAndSet(null, RxAndroidSchedulersHook.getDefaultInstance());\n            // We don't return from here but call get() again in case of thread-race so the winner will\n            // always get returned.\n        }\n        return schedulersHook.get();\n    }\n\n    /**\n     * Registers an {@link RxAndroidSchedulersHook} implementation as a global override of any\n     * injected or default implementations.\n     *\n     * @throws IllegalStateException if called more than once or after the default was initialized\n     * (if usage occurs before trying to register)\n     */\n    public void registerSchedulersHook(RxAndroidSchedulersHook impl) {\n        if (!schedulersHook.compareAndSet(null, impl)) {\n            throw new IllegalStateException(\n                    \"Another strategy was already registered: \" + schedulersHook.get());\n        }\n    }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxandroid/RxAndroidSchedulersHook.java",
    "content": "/*\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.oreilly.rxjava.ch8.rxandroid;\n\nimport rx.Scheduler;\nimport rx.functions.Action0;\n\npublic class RxAndroidSchedulersHook {\n    private static final RxAndroidSchedulersHook DEFAULT_INSTANCE = new RxAndroidSchedulersHook();\n\n    public static RxAndroidSchedulersHook getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    /**\n     * Scheduler to return from {@link AndroidSchedulers#mainThread()} or {@code null} if default\n     * should be used.\n     * <p>\n     * This instance should be or behave like a stateless singleton.\n     */\n    public Scheduler getMainThreadScheduler() {\n        return null;\n    }\n\n    /**\n     * Invoked before the Action is handed over to the scheduler.  Can be used for\n     * wrapping/decorating/logging. The default is just a passthrough.\n     *\n     * @param action action to schedule\n     * @return wrapped action to schedule\n     */\n    public Action0 onSchedule(Action0 action) {\n        return action;\n    }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/RxTextView.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxbinding.internal.Functions;\nimport rx.Observable;\nimport rx.functions.Action1;\nimport rx.functions.Func1;\n\nimport javax.annotation.Nonnull;\n\nimport static com.oreilly.rxjava.ch8.rxbinding.internal.Preconditions.checkNotNull;\n\n\n/**\n * Static factory methods for creating {@linkplain Observable observables} and {@linkplain Action1\n * actions} for {@link TextView}.\n */\npublic final class RxTextView {\n  /**\n   * Create an observable of editor actions on {@code view}.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Warning:</em> The created observable uses {@link TextView.OnEditorActionListener} to\n   * observe actions. Only one observable can be used for a view at a time.\n   */\n  @Nonnull\n  public static Observable<Integer> editorActions(@Nonnull TextView view) {\n    checkNotNull(view, \"view == null\");\n    return editorActions(view, Functions.FUNC1_ALWAYS_TRUE);\n  }\n\n  /**\n   * Create an observable of editor actions on {@code view}.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Warning:</em> The created observable uses {@link TextView.OnEditorActionListener} to\n   * observe actions. Only one observable can be used for a view at a time.\n   *\n   * @param handled Function invoked each occurrence to determine the return value of the\n   * underlying {@link TextView.OnEditorActionListener}.\n   */\n  @Nonnull\n  public static Observable<Integer> editorActions(@Nonnull TextView view,\n      @Nonnull Func1<? super Integer, Boolean> handled) {\n    checkNotNull(view, \"view == null\");\n    checkNotNull(handled, \"handled == null\");\n    return Observable.create(new TextViewEditorActionOnSubscribe(view, handled));\n  }\n\n  /**\n   * Create an observable of editor action events on {@code view}.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Warning:</em> The created observable uses {@link TextView.OnEditorActionListener} to\n   * observe actions. Only one observable can be used for a view at a time.\n   */\n  @Nonnull\n  public static Observable<TextViewEditorActionEvent> editorActionEvents(@Nonnull TextView view) {\n    checkNotNull(view, \"view == null\");\n    return editorActionEvents(view, Functions.FUNC1_ALWAYS_TRUE);\n  }\n\n  /**\n   * Create an observable of editor action events on {@code view}.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Warning:</em> The created observable uses {@link TextView.OnEditorActionListener} to\n   * observe actions. Only one observable can be used for a view at a time.\n   *\n   * @param handled Function invoked each occurrence to determine the return value of the\n   * underlying {@link TextView.OnEditorActionListener}.\n   */\n  @Nonnull\n  public static Observable<TextViewEditorActionEvent> editorActionEvents(@Nonnull TextView view,\n      @Nonnull Func1<? super TextViewEditorActionEvent, Boolean> handled) {\n    checkNotNull(view, \"view == null\");\n    checkNotNull(handled, \"handled == null\");\n    return Observable.create(new TextViewEditorActionEventOnSubscribe(view, handled));\n  }\n\n  /**\n   * Create an observable of character sequences for text changes on {@code view}.\n   * <p>\n   * <em>Warning:</em> Values emitted by this observable are <b>mutable</b> and owned by the host\n   * {@code TextView} and thus are <b>not safe</b> to cache or delay reading (such as by observing\n   * on a different thread). If you want to cache or delay reading the items emitted then you must\n   * map values through a function which calls {@link String#valueOf} or\n   * {@link CharSequence#toString() .toString()} to create a copy.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Note:</em> A value will be emitted immediately on subscribe.\n   */\n  @Nonnull\n  public static Observable<CharSequence> textChanges(@Nonnull TextView view) {\n    checkNotNull(view, \"view == null\");\n    return Observable.create(new TextViewTextOnSubscribe(view));\n  }\n\n  /**\n   * Create an observable of text change events for {@code view}.\n   * <p>\n   * <em>Warning:</em> Values emitted by this observable contain a <b>mutable</b>\n   * {@link CharSequence} owned by the host {@code TextView} and thus are <b>not safe</b> to cache\n   * or delay reading (such as by observing on a different thread). If you want to cache or delay\n   * reading the items emitted then you must map values through a function which calls\n   * {@link String#valueOf} or {@link CharSequence#toString() .toString()} to create a copy.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Note:</em> A value will be emitted immediately on subscribe.\n   */\n  @Nonnull\n  public static Observable<TextViewTextChangeEvent> textChangeEvents(@Nonnull TextView view) {\n    checkNotNull(view, \"view == null\");\n    return Observable.create(new TextViewTextChangeEventOnSubscribe(view));\n  }\n\n  /**\n   * Create an observable of before text change events for {@code view}.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Note:</em> A value will be emitted immediately on subscribe.\n   */\n  @Nonnull\n  public static Observable<TextViewBeforeTextChangeEvent> beforeTextChangeEvents(\n      @Nonnull TextView view) {\n    checkNotNull(view, \"view == null\");\n    return Observable.create(new TextViewBeforeTextChangeEventOnSubscribe(view));\n  }\n\n  /**\n   * Create an observable of after text change events for {@code view}.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Note:</em> A value will be emitted immediately on subscribe.\n   */\n  @Nonnull\n  public static Observable<TextViewAfterTextChangeEvent> afterTextChangeEvents(\n      @Nonnull TextView view) {\n    checkNotNull(view, \"view == null\");\n    return Observable.create(new TextViewAfterTextChangeEventOnSubscribe(view));\n  }\n\n  /**\n   * An action which sets the text property of {@code view} with character sequences.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super CharSequence> text(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<CharSequence>() {\n      @Override public void call(CharSequence text) {\n        view.setText(text);\n      }\n    };\n  }\n\n  /**\n   * An action which sets the text property of {@code view} string resource IDs.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super Integer> textRes(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<Integer>() {\n      @Override public void call(Integer textRes) {\n        view.setText(textRes);\n      }\n    };\n  }\n\n  /**\n   * An action which sets the error property of {@code view} with character sequences.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super CharSequence> error(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<CharSequence>() {\n      @Override public void call(CharSequence text) {\n        view.setError(text);\n      }\n    };\n  }\n\n  /**\n   * An action which sets the error property of {@code view} string resource IDs.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super Integer> errorRes(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<Integer>() {\n      @Override public void call(Integer textRes) {\n        view.setError(view.getContext().getResources().getText(textRes));\n      }\n    };\n  }\n\n  /**\n   * An action which sets the hint property of {@code view} with character sequences.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super CharSequence> hint(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<CharSequence>() {\n      @Override public void call(CharSequence hint) {\n        view.setHint(hint);\n      }\n    };\n  }\n\n  /**\n   * An action which sets the hint property of {@code view} string resource IDs.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super Integer> hintRes(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<Integer>() {\n      @Override public void call(Integer hintRes) {\n        view.setHint(hintRes);\n      }\n    };\n  }\n\n  /**\n   * An action which sets the color property of {@code view} with color integer.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   */\n  @Nonnull\n  public static Action1<? super Integer> color(@Nonnull final TextView view) {\n    checkNotNull(view, \"view == null\");\n    return new Action1<Integer>() {\n      @Override public void call(Integer color) {\n        view.setTextColor(color);\n      }\n    };\n  }\n\n  private RxTextView() {\n    throw new AssertionError(\"No instances.\");\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/RxView.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.view.View;\nimport rx.Observable;\nimport rx.functions.Action1;\n\nimport javax.annotation.Nonnull;\n\nimport static com.oreilly.rxjava.ch8.rxbinding.internal.Preconditions.checkNotNull;\n\n\n/**\n * Static factory methods for creating {@linkplain Observable observables} and {@linkplain Action1\n * actions} for {@link View}.\n */\npublic final class RxView {\n\n  /**\n   * Create an observable which emits on {@code view} click events. The emitted value is\n   * unspecified and should only be used as notification.\n   * <p>\n   * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe\n   * to free this reference.\n   * <p>\n   * <em>Warning:</em> The created observable uses {@link View#setOnClickListener} to observe\n   * clicks. Only one observable can be used for a view at a time.\n   */\n  @Nonnull\n  public static Observable<Void> clicks(@Nonnull View view) {\n    checkNotNull(view, \"view == null\");\n    return Observable.create(new ViewClickOnSubscribe(view));\n  }\n\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewAfterTextChangeEvent.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.content.Context;\nimport android.text.Editable;\nimport android.widget.TextView;\n\nimport javax.annotation.Nonnull;\nimport javax.annotation.Nullable;\n\n/**\n * An after text-change event on a view.\n * <p>\n * <strong>Warning:</strong> Instances keep a strong reference to the view. Operators that cache\n * instances have the potential to leak the associated {@link Context}.\n */\npublic final class TextViewAfterTextChangeEvent extends ViewEvent<TextView> {\n  @Nonnull\n  public static TextViewAfterTextChangeEvent create(@Nonnull TextView view,\n      @Nullable Editable editable) {\n    return new TextViewAfterTextChangeEvent(view, editable);\n  }\n\n  private final Editable editable;\n\n  private TextViewAfterTextChangeEvent(@Nonnull TextView view, @Nullable Editable editable) {\n    super(view);\n    this.editable = editable;\n  }\n\n  @Nullable\n  public Editable editable() {\n    return editable;\n  }\n\n  @Override public boolean equals(Object o) {\n    if (o == this) return true;\n    if (!(o instanceof TextViewAfterTextChangeEvent)) return false;\n    TextViewAfterTextChangeEvent other = (TextViewAfterTextChangeEvent) o;\n    return other.view() == view()\n        && editable.equals(other.editable);\n  }\n\n  @Override public int hashCode() {\n    int result = 17;\n    result = result * 37 + view().hashCode();\n    result = result * 37 + editable.hashCode();\n    return result;\n  }\n\n  @Override public String toString() {\n    return \"TextViewAfterTextChangeEvent{editable=\"\n        + editable\n        + \", view=\"\n        + view()\n        + '}';\n  }\n\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewAfterTextChangeEventOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class TextViewAfterTextChangeEventOnSubscribe\n    implements Observable.OnSubscribe<TextViewAfterTextChangeEvent> {\n  final TextView view;\n\n  TextViewAfterTextChangeEventOnSubscribe(TextView view) {\n    this.view = view;\n  }\n\n  @Override public void call(final Subscriber<? super TextViewAfterTextChangeEvent> subscriber) {\n    verifyMainThread();\n\n    final TextWatcher watcher = new TextWatcher() {\n      @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n      }\n\n      @Override public void onTextChanged(CharSequence s, int start, int before, int count) {\n      }\n\n      @Override public void afterTextChanged(Editable s) {\n        if (!subscriber.isUnsubscribed()) {\n          subscriber.onNext(TextViewAfterTextChangeEvent.create(view, s));\n        }\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.removeTextChangedListener(watcher);\n      }\n    });\n\n    view.addTextChangedListener(watcher);\n\n    // Emit initial value.\n    subscriber.onNext(TextViewAfterTextChangeEvent.create(view, view.getEditableText()));\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewBeforeTextChangeEvent.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.content.Context;\nimport android.widget.TextView;\n\nimport javax.annotation.Nonnull;\n\n/**\n * A before text-change event on a view.\n * <p>\n * <strong>Warning:</strong> Instances keep a strong reference to the view. Operators that cache\n * instances have the potential to leak the associated {@link Context}.\n */\npublic final class TextViewBeforeTextChangeEvent extends ViewEvent<TextView> {\n   @Nonnull\n  public static TextViewBeforeTextChangeEvent create(@Nonnull TextView view,\n      @Nonnull CharSequence text, int start, int count, int after) {\n    return new TextViewBeforeTextChangeEvent(view, text, start, count, after);\n  }\n\n  private final CharSequence text;\n  private final int start;\n  private final int count;\n  private final int after;\n\n  private TextViewBeforeTextChangeEvent(@Nonnull TextView view, @Nonnull CharSequence text,\n      int start, int count, int after) {\n    super(view);\n    this.text = text;\n    this.start = start;\n    this.count = count;\n    this.after = after;\n  }\n\n  @Nonnull\n  public CharSequence text() {\n    return text;\n  }\n\n  public int start() {\n    return start;\n  }\n\n  public int count() {\n    return count;\n  }\n\n  public int after() {\n    return after;\n  }\n\n  @Override public boolean equals(Object o) {\n    if (o == this) return true;\n    if (!(o instanceof TextViewAfterTextChangeEvent)) return false;\n    TextViewBeforeTextChangeEvent other = (TextViewBeforeTextChangeEvent) o;\n    return other.view() == view()\n        && text.equals(other.text)\n        && start == other.start\n        && count == other.count\n        && after == other.after;\n  }\n\n  @Override public int hashCode() {\n    int result = 17;\n    result = result * 37 + view().hashCode();\n    result = result * 37 + text.hashCode();\n    result = result * 37 + start;\n    result = result * 37 + count;\n    result = result * 37 + after;\n    return result;\n  }\n\n  @Override public String toString() {\n    return \"TextViewBeforeTextChangeEvent{text=\"\n        + text\n        + \", start=\"\n        + start\n        + \", count=\"\n        + count\n        + \", after=\"\n        + after\n        + \", view=\"\n        + view()\n        + '}';\n  }\n\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewBeforeTextChangeEventOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class TextViewBeforeTextChangeEventOnSubscribe\n    implements Observable.OnSubscribe<TextViewBeforeTextChangeEvent> {\n  final TextView view;\n\n  TextViewBeforeTextChangeEventOnSubscribe(TextView view) {\n    this.view = view;\n  }\n\n  @Override public void call(final Subscriber<? super TextViewBeforeTextChangeEvent> subscriber) {\n    verifyMainThread();\n\n    final TextWatcher watcher = new TextWatcher() {\n      @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n        if (!subscriber.isUnsubscribed()) {\n          subscriber.onNext(TextViewBeforeTextChangeEvent.create(view, s, start, count, after));\n        }\n      }\n\n      @Override public void onTextChanged(CharSequence s, int start, int before, int count) {\n      }\n\n      @Override public void afterTextChanged(Editable s) {\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.removeTextChangedListener(watcher);\n      }\n    });\n\n    view.addTextChangedListener(watcher);\n\n    // Emit initial value.\n    subscriber.onNext(TextViewBeforeTextChangeEvent.create(view, view.getText(), 0, 0, 0));\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewEditorActionEvent.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.view.KeyEvent;\nimport android.widget.TextView;\n\nimport javax.annotation.Nullable;\n\npublic final class TextViewEditorActionEvent extends ViewEvent<TextView> {\n\n  public static TextViewEditorActionEvent create( TextView view, int actionId,\n      @Nullable KeyEvent keyEvent) {\n    return new TextViewEditorActionEvent(view, actionId, keyEvent);\n  }\n\n  private final int actionId;\n  @Nullable private final KeyEvent keyEvent;\n\n  private TextViewEditorActionEvent( TextView view, int actionId,\n      @Nullable KeyEvent keyEvent) {\n    super(view);\n    this.actionId = actionId;\n    this.keyEvent = keyEvent;\n  }\n\n  public int actionId() {\n    return actionId;\n  }\n\n  @Nullable public KeyEvent keyEvent() {\n    return keyEvent;\n  }\n\n  @Override public boolean equals(Object o) {\n    if (o == this) return true;\n    if (!(o instanceof TextViewEditorActionEvent)) return false;\n    TextViewEditorActionEvent other = (TextViewEditorActionEvent) o;\n    return other.view() == view()\n        && other.actionId == actionId\n        && (other.keyEvent != null ? other.keyEvent.equals(keyEvent) : keyEvent == null);\n  }\n\n  @Override public int hashCode() {\n    int result = 17;\n    result = result * 37 + view().hashCode();\n    result = result * 37 + actionId;\n    result = result * 37 + (keyEvent != null ? keyEvent.hashCode() : 0);\n    return result;\n  }\n\n  @Override public String toString() {\n    return \"TextViewEditorActionEvent{view=\"\n        + view()\n        + \", actionId=\"\n        + actionId\n        + \", keyEvent=\"\n        + keyEvent\n        + '}';\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewEditorActionEventOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.view.KeyEvent;\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func1;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class TextViewEditorActionEventOnSubscribe\n    implements Observable.OnSubscribe<TextViewEditorActionEvent> {\n  final TextView view;\n  final Func1<? super TextViewEditorActionEvent, Boolean> handled;\n\n  TextViewEditorActionEventOnSubscribe(TextView view,\n      Func1<? super TextViewEditorActionEvent, Boolean> handled) {\n    this.view = view;\n    this.handled = handled;\n  }\n\n  @Override public void call(final Subscriber<? super TextViewEditorActionEvent> subscriber) {\n    verifyMainThread();\n\n    TextView.OnEditorActionListener listener = new TextView.OnEditorActionListener() {\n      @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) {\n        TextViewEditorActionEvent event = TextViewEditorActionEvent.create(v, actionId, keyEvent);\n        if (handled.call(event)) {\n          if (!subscriber.isUnsubscribed()) {\n            subscriber.onNext(event);\n          }\n          return true;\n        }\n        return false;\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.setOnEditorActionListener(null);\n      }\n    });\n\n    view.setOnEditorActionListener(listener);\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewEditorActionOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.view.KeyEvent;\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func1;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class TextViewEditorActionOnSubscribe implements Observable.OnSubscribe<Integer> {\n  final TextView view;\n  final Func1<? super Integer, Boolean> handled;\n\n  TextViewEditorActionOnSubscribe(TextView view, Func1<? super Integer, Boolean> handled) {\n    this.view = view;\n    this.handled = handled;\n  }\n\n  @Override public void call(final Subscriber<? super Integer> subscriber) {\n    verifyMainThread();\n\n    TextView.OnEditorActionListener listener = new TextView.OnEditorActionListener() {\n      @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {\n        if (handled.call(actionId)) {\n          if (!subscriber.isUnsubscribed()) {\n            subscriber.onNext(actionId);\n          }\n          return true;\n        }\n        return false;\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.setOnEditorActionListener(null);\n      }\n    });\n\n    view.setOnEditorActionListener(listener);\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewTextChangeEvent.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.content.Context;\nimport android.widget.TextView;\n\nimport javax.annotation.Nonnull;\n\n/**\n * A text-change event on a view.\n * <p>\n * <strong>Warning:</strong> Instances keep a strong reference to the view. Operators that cache\n * instances have the potential to leak the associated {@link Context}.\n */\npublic final class TextViewTextChangeEvent extends ViewEvent<TextView> {\n  @Nonnull\n  public static TextViewTextChangeEvent create(@Nonnull TextView view, @Nonnull CharSequence text,\n                                               int start, int before, int count) {\n    return new TextViewTextChangeEvent(view, text, start, before, count);\n  }\n\n  private final CharSequence text;\n  private final int start;\n  private final int before;\n  private final int count;\n\n  private TextViewTextChangeEvent(@Nonnull TextView view, @Nonnull CharSequence text, int start,\n      int before, int count) {\n    super(view);\n    this.text = text;\n    this.start = start;\n    this.before = before;\n    this.count = count;\n  }\n\n  @Nonnull\n  public CharSequence text() {\n    return text;\n  }\n\n  public int start() {\n    return start;\n  }\n\n  public int before() {\n    return before;\n  }\n\n  public int count() {\n    return count;\n  }\n\n  @Override public boolean equals(Object o) {\n    if (o == this) return true;\n    if (!(o instanceof TextViewTextChangeEvent)) return false;\n    TextViewTextChangeEvent other = (TextViewTextChangeEvent) o;\n    return other.view() == view()\n        && text.equals(other.text)\n        && start == other.start\n        && before == other.before\n        && count == other.count;\n  }\n\n  @Override public int hashCode() {\n    int result = 17;\n    result = result * 37 + view().hashCode();\n    result = result * 37 + text.hashCode();\n    result = result * 37 + start;\n    result = result * 37 + before;\n    result = result * 37 + count;\n    return result;\n  }\n\n  @Override public String toString() {\n    return \"TextViewTextChangeEvent{text=\"\n        + text\n        + \", start=\"\n        + start\n        + \", before=\"\n        + before\n        + \", count=\"\n        + count\n        + \", view=\"\n        + view()\n        + '}';\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewTextChangeEventOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class TextViewTextChangeEventOnSubscribe\n    implements Observable.OnSubscribe<TextViewTextChangeEvent> {\n  final TextView view;\n\n  TextViewTextChangeEventOnSubscribe(TextView view) {\n    this.view = view;\n  }\n\n  @Override public void call(final Subscriber<? super TextViewTextChangeEvent> subscriber) {\n    verifyMainThread();\n\n    final TextWatcher watcher = new TextWatcher() {\n      @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n      }\n\n      @Override public void onTextChanged(CharSequence s, int start, int before, int count) {\n        if (!subscriber.isUnsubscribed()) {\n          subscriber.onNext(TextViewTextChangeEvent.create(view, s, start, before, count));\n        }\n      }\n\n      @Override public void afterTextChanged(Editable s) {\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.removeTextChangedListener(watcher);\n      }\n    });\n\n    view.addTextChangedListener(watcher);\n\n    // Emit initial value.\n    subscriber.onNext(TextViewTextChangeEvent.create(view, view.getText(), 0, 0, 0));\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/TextViewTextOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.widget.TextView;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class TextViewTextOnSubscribe implements Observable.OnSubscribe<CharSequence> {\n  final TextView view;\n\n  TextViewTextOnSubscribe(TextView view) {\n    this.view = view;\n  }\n\n  @Override public void call(final Subscriber<? super CharSequence> subscriber) {\n    verifyMainThread();\n\n    final TextWatcher watcher = new TextWatcher() {\n      @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n      }\n\n      @Override public void onTextChanged(CharSequence s, int start, int before, int count) {\n        if (!subscriber.isUnsubscribed()) {\n          subscriber.onNext(s);\n        }\n      }\n\n      @Override public void afterTextChanged(Editable s) {\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.removeTextChangedListener(watcher);\n      }\n    });\n\n    view.addTextChangedListener(watcher);\n\n    // Emit initial value.\n    subscriber.onNext(view.getText());\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/ViewClickOnSubscribe.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.view.View;\nimport com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription;\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport static com.oreilly.rxjava.ch8.rxandroid.MainThreadSubscription.verifyMainThread;\n\nfinal class ViewClickOnSubscribe implements Observable.OnSubscribe<Void> {\n  final View view;\n\n  ViewClickOnSubscribe(View view) {\n    this.view = view;\n  }\n\n  @Override public void call(final Subscriber<? super Void> subscriber) {\n    verifyMainThread();\n\n    View.OnClickListener listener = new View.OnClickListener() {\n      @Override public void onClick(View v) {\n        if (!subscriber.isUnsubscribed()) {\n          subscriber.onNext(null);\n        }\n      }\n    };\n\n    subscriber.add(new MainThreadSubscription() {\n      @Override protected void onUnsubscribe() {\n        view.setOnClickListener(null);\n      }\n    });\n\n    view.setOnClickListener(listener);\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/ViewEvent.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding;\n\nimport android.content.Context;\nimport android.view.View;\n\nimport javax.annotation.Nonnull;\n\nimport static com.oreilly.rxjava.ch8.rxbinding.internal.Preconditions.checkNotNull;\n\n/**\n * A target view on which an event occurred (e.g., click).\n * <p>\n * <strong>Warning:</strong> Instances keep a strong reference to the view. Operators that cache\n * instances have the potential to leak the associated {@link Context}.\n */\npublic abstract class ViewEvent<T extends View> {\n  private final T view;\n\n  protected ViewEvent(@Nonnull T view) {\n    this.view = checkNotNull(view, \"view == null\");\n  }\n\n  /** The view from which this event occurred. */\n  @Nonnull public T view() {\n    return view;\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/internal/Functions.java",
    "content": "package com.oreilly.rxjava.ch8.rxbinding.internal;\n\nimport rx.functions.Func0;\nimport rx.functions.Func1;\n\npublic final class Functions {\n  private static final Always<Boolean> ALWAYS_TRUE = new Always<>(true);\n  public static final Func0<Boolean> FUNC0_ALWAYS_TRUE = ALWAYS_TRUE;\n  public static final Func1<Object, Boolean> FUNC1_ALWAYS_TRUE = ALWAYS_TRUE;\n\n  private static final class Always<T> implements Func1<Object, T>, Func0<T> {\n    private final T value;\n\n    Always(T value) {\n      this.value = value;\n    }\n\n    @Override public T call(Object o) {\n      return value;\n    }\n\n    @Override public T call() {\n      return value;\n    }\n  }\n\n  private Functions() {\n    throw new AssertionError(\"No instances.\");\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch8/rxbinding/internal/Preconditions.java",
    "content": "/*\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.oreilly.rxjava.ch8.rxbinding.internal;\n\npublic final class Preconditions {\n  public static void checkArgument(boolean assertion, String message) {\n    if (!assertion) {\n      throw new IllegalArgumentException(message);\n    }\n  }\n\n  public static <T> T checkNotNull(T value, String message) {\n    if (value == null) {\n      throw new NullPointerException(message);\n    }\n    return value;\n  }\n\n  private Preconditions() {\n    throw new AssertionError(\"No instances.\");\n  }\n}"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/ch9/Chapter9.java",
    "content": "package com.oreilly.rxjava.ch9;\n\nimport org.junit.Ignore;\n\n@Ignore\npublic class Chapter9 {\n\n\t//no samples in this chapter\n\n}\n"
  },
  {
    "path": "src/test/java/com/oreilly/rxjava/util/Sleeper.java",
    "content": "package com.oreilly.rxjava.util;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.time.Duration;\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\npublic class Sleeper {\n\n\tprivate static final Logger log = LoggerFactory.getLogger(Sleeper.class);\n\tpublic static final Random RAND = new Random();\n\n\tpublic static void sleep(Duration duration, Duration stdDev) {\n\t\tdouble randMillis = Math.max(0, duration.toMillis() + RAND.nextGaussian() * stdDev.toMillis());\n\t\tsleep(Duration.ofMillis((long) randMillis));\n\t}\n\n\tpublic static void sleep(Duration duration) {\n\t\ttry {\n\t\t\tTimeUnit.MILLISECONDS.sleep(duration.toMillis());\n\t\t} catch (InterruptedException e) {\n\t\t\tlog.warn(\"Sleep interrupted\", e);\n\t\t}\n\t}\n\n}"
  }
]