Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Screen_capture_lite | 519 | a month ago | 15 | mit | C | |||||
cross platform screen/window capturing library | ||||||||||
Quicklib | 478 | a month ago | 29 | apache-2.0 | Pascal | |||||
Quick development library (AutoMapper, LinQ, IOC Dependency Injection, MemoryCache, Scheduled tasks, Json and Yml Config and Options pattern, Serializers, etc) with crossplatform support for Delphi/Firemonkey (Windows,Linux,OSX/IOS/Android) and freepascal (Windows/Linux). | ||||||||||
Adi | 221 | a year ago | 1 | October 14, 2019 | 3 | apache-2.0 | C | |||
ADI(Android Debug Intensive) 是通过 JVMTI 实现的 Android 应用开发调试的增强工具集,目前主要提供性能相关的监控能力。 | ||||||||||
Lagmonitor | 186 | 2 months ago | 27 | mit | Java | |||||
Monitor performance of your Minecraft server. Similar to VisualVM and Java Mission Control. | ||||||||||
Chronicle Threads | 136 | 17 | 4 | 2 days ago | 203 | August 24, 2022 | 7 | other | Java | |
Source Chat Relay | 78 | 14 days ago | 41 | gpl-3.0 | Rust | |||||
Communicate between Discord & In-Game, monitor server without being in-game, control the flow of messages and user base engagement! | ||||||||||
Threaddebugger | 75 | 1 | 1 | 3 years ago | 12 | December 15, 2019 | 3 | apache-2.0 | Java | |
Threads monitor and the thread pool factory. | ||||||||||
Jamonapi | 56 | a year ago | 13 | Java | ||||||
Another repo for jamonapi.com which is primarily hosted on sourceforge | ||||||||||
Anreye | 49 | 5 | 5 years ago | 5 | October 22, 2018 | 1 | mit | Objective-C | ||
Class for monitor excessive blocking on the main thread and return stacktrace of all threads | ||||||||||
Wdm | 41 | 9,537 | 27 | 7 years ago | 5 | July 09, 2015 | 15 | mit | C | |
Windows Directory Monitor (WDM) is a threaded directories monitor for Windows. |
This Github includes: Threads debugger(threaddebugger)、Thread pool factory(threadpools).
There are several ways to debugger the activity of threads in the application, such as the Allocation Tracking from Android Studio Monitor by the way there are information about the running threads, or recording the Method Profiling from the Android Device Monitor by the way it also present the running threads information, but they are a little too heavy, and not flexible enough sometimes.
With this ThreadDebugger, you don't need to worry about how long duration you recording, and you can find out the changing of the threads activity very easy.
The executor from this thread pool factory will require each task provide its exact name to facilitate debugging, and making create some thread pools in the common rule very convenient.
ThreadDebugger and ThreadPool is installed by adding the following dependency to your build.gradle
file:
dependencies {
// If you need use ThreadDebugger.
debugImplementation'cn.dreamtobe.threaddebugger:threaddebugger:1.6.3'
releaseImplementation'cn.dreamtobe.threaddebugger:threaddebugger-no-op:1.6.3'
// If you need use ThreadPool.
implementation'cn.dreamtobe.threaddebugger:threadpool:1.6.3'
}
IThreadDebugger debugger = ThreadDebugger.install(
ThreadDebuggers.createWithCommonThreadKey() /** The ThreadDebugger with known thread Categories **/
// add Thread Category
.add("IO", "IO")
.add("computation", "computation")
.add("network", "network")
.add("test1", "test1")
.add("test2", "test2")
.add("test3", "test3")
.add("test4", "test4"),
2000, /** The frequent of Updating Thread Activity information **/
new ThreadDebugger.ThreadChangedCallback() { /** The threads changed callback **/
@Override
public void onChanged(IThreadDebugger debugger) {
// callback this method when the threads in this application has changed.
Log.d(TAG, debugger.drawUpEachThreadInfoDiff());
Log.d(TAG, debugger.drawUpEachThreadSizeDiff());
Log.d(TAG, debugger.drawUpEachThreadSize());
Log.d(TAG, debugger.drawUpEachThreadInfo());
Log.d(TAG, debugger.drawUpUnknownInfo());
}
});
If the time is your consider, please using
adb logcat -v time
instead ofadb logcat -v raw
on bellow commands.
adb logcat -v raw | grep drawUpEachThreadInfoDiff:
drawUpEachThreadInfoDiff: Thread count = 13. Thread differ : +13. main: +1 [(+)main] | Binder: +2 [(+)Binder_2, (+)Binder_1] | Finalizer: +2 [(+)FinalizerWatchdogDaemon, (+)FinalizerDaemon] | RenderThread: +1 [(+)RenderThread] | HeapTaskDaemon: +1 [(+)HeapTaskDaemon] | ReferenceQueueDaemon: +1 [(+)ReferenceQueueDaemon] | JDWP: +1 [(+)JDWP] | unknown: +4 [(+)hwuiTask1, (+)hwuiTask2, (+)ThreadDebugger, (+)Signal Catcher]
drawUpEachThreadInfoDiff: Thread count = 15. Thread differ : +2. computation: +1 [(+)computation-1::running-Test1:7s] | test1: +1 [(+)test1-ExceedDiscard-1::running-RandomThreadWork]
drawUpEachThreadInfoDiff: Thread count = 16. Thread differ : +1. test1: +1 [(+)test1-ExceedDiscard-2::running-Test2:1s]
drawUpEachThreadInfoDiff: Thread count = 17. Thread differ : +1. computation: +1 [(+)computation-2::running-Test3:8s] | test1: SWAP [(+)test1-ExceedDiscard-2::idle, (-)test1-ExceedDiscard-2::running-Test2:1s]
drawUpEachThreadInfoDiff: Thread count = 17. Thread differ : 0. computation: SWAP [(+)computation-1::idle, (-)computation-1::running-Test1:7s]
drawUpEachThreadInfoDiff: Thread count = 18. Thread differ : +1. computation: +1 [(+)computation-3::running-Test4:9s]
drawUpEachThreadInfoDiff: Thread count = 19. Thread differ : +1. network: +1 [(+)network-1::running-Test5:1s]
drawUpEachThreadInfoDiff: Thread count = 19. Thread differ : 0. network: SWAP [(+)network-1::idle, (-)network-1::running-Test5:1s]
drawUpEachThreadInfoDiff: Thread count = 20. Thread differ : +1. IO: +1 [(+)io-1::running-Test6:1s]
drawUpEachThreadInfoDiff: Thread count = 20. Thread differ : 0. IO: SWAP [(+)io-1::idle, (-)io-1::running-Test6:1s]
drawUpEachThreadInfoDiff: Thread count = 20. Thread differ : 0. computation: SWAP [(+)computation-2::idle, (-)computation-2::running-Test3:8s] | test1: SWAP [(+)test1-ExceedDiscard-1::idle, (-)test1-ExceedDiscard-1::running-RandomThreadWork]
drawUpEachThreadInfoDiff: Thread count = 20. Thread differ : 0. computation: SWAP [(+)computation-3::idle, (-)computation-3::running-Test4:9s]
adb logcat -v raw | grep drawUpEachThreadSizeDiff:
drawUpEachThreadSizeDiff: Thread count = 13. Thread differ : +13. main: +1 | Binder: +2 | Finalizer: +2 | RenderThread: +1 | HeapTaskDaemon: +1 | ReferenceQueueDaemon: +1 | JDWP: +1 | unknown: +4 [(+)hwuiTask1, (+)hwuiTask2, (+)ThreadDebugger, (+)Signal Catcher]
drawUpEachThreadSizeDiff: Thread count = 15. Thread differ : +2. computation: +1 | test1: +1
drawUpEachThreadSizeDiff: Thread count = 16. Thread differ : +1. test1: +1
drawUpEachThreadSizeDiff: Thread count = 17. Thread differ : +1. computation: +1
drawUpEachThreadSizeDiff: Thread count = 17. Thread size has not changed.
drawUpEachThreadSizeDiff: Thread count = 18. Thread differ : +1. computation: +1
drawUpEachThreadSizeDiff: Thread count = 19. Thread differ : +1. network: +1
drawUpEachThreadSizeDiff: Thread count = 19. Thread size has not changed.
drawUpEachThreadSizeDiff: Thread count = 20. Thread differ : +1. IO: +1
drawUpEachThreadSizeDiff: Thread count = 20. Thread size has not changed.
drawUpEachThreadSizeDiff: Thread count = 20. Thread size has not changed.
drawUpEachThreadSizeDiff: Thread count = 20. Thread size has not changed.
adb logcat -v raw | grep drawUpEachThreadSize:
drawUpEachThreadSize: Thread count = 13. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | unknown: 4
drawUpEachThreadSize: Thread count = 15. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 1 | test1: 1 | unknown: 4
drawUpEachThreadSize: Thread count = 16. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 1 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 17. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 2 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 17. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 2 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 18. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 3 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 19. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 3 | network: 1 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 19. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | computation: 3 | network: 1 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 20. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | IO: 1 | computation: 3 | network: 1 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 20. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | IO: 1 | computation: 3 | network: 1 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 20. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | IO: 1 | computation: 3 | network: 1 | test1: 2 | unknown: 4
drawUpEachThreadSize: Thread count = 20. main: 1 | Binder: 2 | Finalizer: 2 | RenderThread: 1 | HeapTaskDaemon: 1 | ReferenceQueueDaemon: 1 | JDWP: 1 | IO: 1 | computation: 3 | network: 1 | test1: 2 | unknown: 4
adb logcat -v raw | grep drawUpEachThreadInfo:
drawUpEachThreadInfo: Thread count = 13. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerWatchdogDaemon, FinalizerDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | unknown[hwuiTask1, hwuiTask2, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 15. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::running-Test1:7s] | test1[test1-ExceedDiscard-1::running-RandomThreadWork] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 16. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::running-Test1:7s] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::running-Test2:1s] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 17. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::running-Test1:7s, computation-2::running-Test3:8s] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 17. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::idle, computation-2::running-Test3:8s] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 18. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::idle, computation-2::running-Test3:8s, computation-3::running-Test4:9s] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 19. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::idle, computation-2::running-Test3:8s, computation-3::running-Test4:9s] | network[network-1::running-Test5:1s] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 19. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | computation[computation-1::idle, computation-2::running-Test3:8s, computation-3::running-Test4:9s] | network[network-1::idle] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 20. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | IO[io-1::running-Test6:1s] | computation[computation-1::idle, computation-2::running-Test3:8s, computation-3::running-Test4:9s] | network[network-1::idle] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 20. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | IO[io-1::idle] | computation[computation-1::idle, computation-2::running-Test3:8s, computation-3::running-Test4:9s] | network[network-1::idle] | test1[test1-ExceedDiscard-1::running-RandomThreadWork, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 20. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | IO[io-1::idle] | computation[computation-1::idle, computation-2::idle, computation-3::running-Test4:9s] | network[network-1::idle] | test1[test1-ExceedDiscard-1::idle, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpEachThreadInfo: Thread count = 20. main[main] | Binder[Binder_2, Binder_1] | Finalizer[FinalizerDaemon, FinalizerWatchdogDaemon] | RenderThread[RenderThread] | HeapTaskDaemon[HeapTaskDaemon] | ReferenceQueueDaemon[ReferenceQueueDaemon] | JDWP[JDWP] | IO[io-1::idle] | computation[computation-1::idle, computation-2::idle, computation-3::idle] | network[network-1::idle] | test1[test1-ExceedDiscard-1::idle, test1-ExceedDiscard-2::idle] | unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
adb logcat -v raw | grep drawUpUnknownInfo:
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = +4. unknown[hwuiTask1, hwuiTask2, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
drawUpUnknownInfo: Unknow thread count = 4. Unknow thread differ = 0. unknown[hwuiTask2, hwuiTask1, ThreadDebugger, Signal Catcher]
Method | Function |
---|---|
add(key:String) | add the thread category with the key used to compare the start of thread-name and also as its alias to the Debugger. |
add(startWithKey:String , alias:String) | add the thread category with the startWithKey and its alias to the Debugger. |
refresh() | Refresh threads situation. |
drawUpEachThreadSize() | the content of the size of each thread. |
drawUpEachThreadInfo() | the content of the information of each thread. |
drawUpEachThreadSizeDiff() | the content of the changed size of each changed thread. |
drawUpEachThreadInfoDiff() | the content of the information of the each changed thread. |
drawUpUnknownInfo() | the content of unknown threads info. |
isSizeChanged() | Whether threads size has changed. |
isChanged() | Whether threads has changed. |
The executor from this thread pool factory will require each task in it to provide its exact name to facilitate debugging.
- Entrance: ThreadPools
- Demo: DemoThreadPoolCentral
When a new task is submitted in method execute(Runnable)
, and fewer than corePoolSize
threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize
but less than maximumPoolSize
threads running, a new thread is created to handle the request too, but when it turn to idle and the interval time of waiting for new tasks more than keepAliveTime
, it will be terminate to reduce the cost of resources.
Method | Function |
---|---|
newExceedWaitPool | Under the premise of satisfying the Basic Rules, if there are maximumPoolSize tasks running, the further task will be enqueued to the waiting queue, and will be executed when the size of running tasks less than maximumPoolSize . |
newExceedDiscardPool | Under the premise of satisfying the Basic Rules, if there are maximumPoolSize tasks running, the further task will be discard. |
newExceedCallerRunsPool | Under the premise of satisfying the Basic Rules, if there are maximumPoolSize tasks running, the further task will be executed immediately in the caller thread. |
newExceedCallImmediatelyPool | Under the premise of satisfying the Basic Rules, if there are maximumPoolSize tasks running, the further task will be executed immediately in the global temporary unbound thread pool. |
newSinglePool | The same to the java.util.concurrent.Executors#newSingleThreadExecutor() . |
newFixedPool | The same to the java.util.concurrent.Executors#newFixedThreadPool(int) . |
newCachedPool | The same to the java.util.concurrent.Executors#newCachedThreadPool() . |
newNoCorePool | If there are threadCount tasks are running, the further task will be enqueued to the waiting queue, and will be executed when the size of running tasks less than threadCount . If the thread in this pool is turn to idle and the interval time of waiting for new tasks more keepAliveTime , it will be terminate to reduce the cost of resources. |
Copyright (C) 2015-2016 Jacksgong(blog.dreamtobe.cn)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.